"""
图表构建器 - 有状态的编排器

这是重构后的核心，使用有状态的构建器模式来编排 oxml 层的调用。
解决 P(n,2) 组合爆炸问题。
"""

from typing import List, Dict, Optional
from pptx.chart.chart import Chart
import pandas as pd
from collections import defaultdict

from .oxml import (
    extract_axis_ids,
    create_value_axis,
    optimize_axis_labels,
    optimize_category_axis,
    create_plot_element,
    add_axis_refs,
    add_plot_categories,
    add_series_to_plot,
)

# 导入样式模块
try:
    from .styles import DEFAULT_STYLE_CONFIG
except ImportError:
    # 如果样式模块不存在，设置为 None
    DEFAULT_STYLE_CONFIG = None


class ChartBuilder:
    """
    有状态的图表构建器
    
    职责：
    1. 管理坐标轴（主轴/次轴）
    2. 按 (type, axis) 分组系列
    3. 委托 oxml 层创建 XML 元素
    
    优势：
    - 解决 P(n,2) 组合问题：不需要为每种组合写代码
    - 只需为每种图表类型实现一次 XML 生成
    - 主函数动态组合它们
    """
    
    def __init__(self, chart: Chart, df: pd.DataFrame, categories_col: str, style_config=None, layout_config=None):
        """
        初始化构建器
        
        Args:
            chart: python-pptx 创建的基础图表（用于激活 XML 结构）
            df: 数据源 DataFrame
            categories_col: 分类列名
            style_config: 样式配置对象（可选，默认使用 DEFAULT_STYLE_CONFIG）
            layout_config: 布局配置对象（可选，包含图例、轴配置）
        """
        self.chart = chart
        self.df = df
        self.categories_col = categories_col
        self.style_config = style_config if style_config is not None else DEFAULT_STYLE_CONFIG
        self.layout_config = layout_config  # 布局配置
        
        # 访问 XML 结构
        self.chartSpace = chart._chartSpace
        self.plotArea = self.chartSpace.plotArea
        
        # 提取现有坐标轴 ID
        self.cat_ax_id, self.pri_val_ax_id = extract_axis_ids(self.plotArea)
        self.sec_val_ax_id = None
        
        # 系列计数器（用于 Excel 列索引）
        self._series_counter = 0
        
        print(f"\n📊 ChartBuilder 初始化完成")
        print(f"  - 分类轴 ID: {self.cat_ax_id}")
        print(f"  - 主值轴 ID: {self.pri_val_ax_id}")
        if self.style_config is not None:
            print(f"  - 样式配置: 已启用")
        else:
            print(f"  - 样式配置: 默认")
        if self.layout_config is not None:
            print(f"  - 布局配置: 已启用")
    
    def ensure_secondary_axis(self) -> int:
        """
        确保次值轴存在（只创建一次）
        
        Returns:
            次值轴 ID
        """
        if self.sec_val_ax_id is None:
            # 生成新的轴 ID
            new_ax_id = max(self.cat_ax_id, self.pri_val_ax_id) + 1000
            
            # ⭐ 创建次值轴（右侧，标签在右边，crosses='max'）
            self.sec_val_ax_id = create_value_axis(
                self.plotArea,
                ax_id=new_ax_id,
                cross_ax_id=self.cat_ax_id,
                position='r',
                tick_label_position='high',
                crosses_at='max'  # 右轴线在图表右边
            )
            
            # ⭐ 优化主值轴（左侧，标签在左边，crosses='min'，移除网格线）
            optimize_axis_labels(
                self.plotArea,
                self.pri_val_ax_id,
                tick_label_position='low',
                crosses_at='min',  # 左轴线在图表左边
                remove_gridlines=True  # 移除内部横框
            )
            
            # ⭐ 优化分类轴（移除日期间的小竖线）
            optimize_category_axis(
                self.plotArea,
                self.cat_ax_id,
                remove_tick_marks=True  # 移除底部日期间的小竖线
            )
            
            print(f"\n⭐ 次值轴已创建")
            print(f"  - 次值轴 ID: {self.sec_val_ax_id}")
            print(f"  - 位置: 右侧 (position='r', crosses='max')")
            print(f"  - 标签: 右侧 (tickLblPos='high')")
            print(f"  - 主值轴已优化: 左侧 (tickLblPos='low', crosses='min')")
        
        return self.sec_val_ax_id
    
    def clear_bootstrap_chart(self):
        """
        清理引导时创建的图表元素
        
        Note: 
            使用 python-pptx 创建基础图表时，会自动创建一个图表元素。
            我们需要清理它，以便完全通过 XML 自定义。
        """
        # 查找并删除 python-pptx 自动创建的图表元素
        # 这些通常是 <c:barChart>, <c:lineChart> 等
        
        # 获取所有可能的图表类型元素
        chart_types = ['barChart', 'lineChart', 'areaChart', 'scatterChart', 'pieChart']
        
        for chart_type in chart_types:
            # 查找所有该类型的图表元素
            elements = self.plotArea.xpath(f'./c:{chart_type}')
            for elem in elements:
                # 删除这个元素
                self.plotArea.remove(elem)
                print(f"  → 清理引导图表元素: <c:{chart_type}>")
        
        print(f"  → 引导图表已清理")
    
    def add_plot(self, series_group: List[Dict], plot_order_index: int = 0):
        """
        添加一组系列（同类型、同轴）
        
        Args:
            series_group: 系列配置列表
                [
                    {"key": "col1", "name": "系列1", "type": "bar", "axis": "primary"},
                    {"key": "col2", "name": "系列2", "type": "bar", "axis": "primary"}
                ]
            plot_order_index: 绘图顺序索引（0=最底层，1=上一层，依此类推）
                
        Notes:
            - 组内所有系列必须有相同的 type 和 axis
            - 会创建一个新的绘图元素 (<c:barChart>, <c:lineChart> 等)
            - 并为每个系列添加 <c:ser> 元素
        """
        if not series_group:
            return
        
        # 从第一个系列获取共享属性
        first_cfg = series_group[0]
        chart_type = first_cfg.get("type", "bar")
        axis_type = first_cfg.get("axis", "primary")
        
        # 决定使用哪个值轴
        if axis_type == 'primary':
            val_ax_id = self.pri_val_ax_id
        elif axis_type == 'secondary':
            val_ax_id = self.ensure_secondary_axis()
        else:
            raise ValueError(f"未知的轴类型: {axis_type}")
        
        print(f"\n➕ 添加绘图组: type={chart_type}, axis={axis_type}, order={plot_order_index}")
        print(f"  - 使用值轴 ID: {val_ax_id}")
        
        # 创建绘图元素（不包含轴引用）
        plot_element = create_plot_element(
            self.plotArea,
            chart_type,
            self.cat_ax_id,
            val_ax_id,
            order_index=plot_order_index  # ⭐ 传递 order_index
        )
        
        # ⭐ 新方案：不在 plot 级别添加共享分类数据
        # 每个系列有自己的 <c:cat> 元素，避免重复
        # categories = self.df[self.categories_col].tolist()
        # add_plot_categories(plot_element, categories)
        # print(f"  - 添加共享分类数据（{len(categories)} 个分类）")
        
        # 为每个系列添加 <c:ser>
        for series_cfg in series_group:
            add_series_to_plot(
                plot_element,
                chart_type,
                series_cfg,
                self._series_counter,
                self.df,
                self.categories_col,
                self.style_config  # ⭐ 传递样式配置
            )
            print(f"  - 添加系列: '{series_cfg['name']}' (索引 {self._series_counter})")
            self._series_counter += 1
        
        # ⭐ 关键修复：在所有系列添加完成后，再添加轴引用
        # 确保 XML 元素顺序正确：<c:cat> <c:ser> ... <c:ser> <c:axId> <c:axId>
        add_axis_refs(plot_element, self.cat_ax_id, val_ax_id)
        print(f"  - 添加轴引用: cat_ax={self.cat_ax_id}, val_ax={val_ax_id}")
    
    def build(self, series_config: List[Dict]):
        """
        构建完整的组合图
        
        Args:
            series_config: 系列配置列表
                [
                    {"key": "col1", "name": "系列1", "type": "bar", "axis": "primary"},
                    {"key": "col2", "name": "系列2", "type": "line", "axis": "secondary"},
                ]
                
        Returns:
            构建后的 Chart 对象
        """
        print("\n" + "=" * 80)
        print("🔨 开始构建组合图")
        print("=" * 80)
        
        # 1. 按 (type, axis) 分组
        plot_groups = self._group_series(series_config)
        
        print(f"\n📦 系列分组结果:")
        for key, group in plot_groups.items():
            print(f"  - {key}: {len(group)} 个系列")
        
        # 2. 清理引导图表（可选）
        self.clear_bootstrap_chart()
        
        # 3. ⭐ 按堆叠顺序添加绘图组
        # 规则：先添加的绘图组在底层，后添加的在上层
        # 策略：先画"背景"（柱状图/面积图），再画"前景"（折线图/散点图）
        plot_order_counter = 0
        
        # 3.1 先添加所有"背景"图表 (bar, area)
        for (plot_type, axis_type), series_group in plot_groups.items():
            if plot_type in ('bar', 'column', 'area'):
                self.add_plot(series_group, plot_order_counter)
                plot_order_counter += 1
        
        # 3.2 再添加所有"前景"图表 (line, scatter)
        for (plot_type, axis_type), series_group in plot_groups.items():
            if plot_type in ('line', 'scatter'):
                self.add_plot(series_group, plot_order_counter)
                plot_order_counter += 1
        
        # 4. ⭐ 应用布局配置（图例、轴格式等）
        if self.layout_config is not None:
            self.layout_config.apply_to_chart(self.chart)

        # 5. ⭐ ChartJunkCleaner: 自动清洗默认 PPT 样式
        try:
            from .cleaner import clean_chart
            clean_chart(self.chart)
            print(f"  → ChartJunkCleaner applied")
        except Exception as e:
            print(f"  → ChartJunkCleaner skipped: {e}")

        print("\n" + "=" * 80)
        print("✅ 组合图构建完成！")
        print("=" * 80)

        return self.chart
    
    @staticmethod
    def _group_series(series_config: List[Dict]) -> Dict[tuple, List[Dict]]:
        """
        按 (type, axis) 分组系列
        
        Args:
            series_config: 系列配置列表
            
        Returns:
            分组后的字典 {(type, axis): [series_cfg, ...]}
            
        Examples:
            输入:
            [
                {"key": "s1", "type": "bar", "axis": "primary"},
                {"key": "s2", "type": "bar", "axis": "primary"},
                {"key": "s3", "type": "line", "axis": "secondary"},
            ]
            
            输出:
            {
                ("bar", "primary"): [{"key": "s1", ...}, {"key": "s2", ...}],
                ("line", "secondary"): [{"key": "s3", ...}]
            }
        """
        groups = defaultdict(list)
        for cfg in series_config:
            key = (cfg.get("type", "bar"), cfg.get("axis", "primary"))
            groups[key].append(cfg)
        return dict(groups)

