"""
公共 API - 简洁的高层接口

这是用户（您的工作室同事）唯一需要导入的模块。
隐藏所有实现细节。
"""

from typing import List, Dict, Optional
from pptx.slide import Slide
from pptx.enum.chart import XL_CHART_TYPE
from pptx.chart.data import CategoryChartData
from pptx.util import Inches
import pandas as pd

from .builder import ChartBuilder

# 导入样式模块
try:
    from .styles import StyleConfig, DEFAULT_STYLE_CONFIG
except ImportError:
    StyleConfig = None
    DEFAULT_STYLE_CONFIG = None

# 导入布局模块
try:
    from .layout import ChartLayoutConfig
except ImportError:
    ChartLayoutConfig = None


def create_combo_chart(
    slide: Slide,
    df: pd.DataFrame,
    categories_col: str,
    series_config: List[Dict],
    position: tuple = (Inches(1), Inches(2)),
    size: tuple = (Inches(8), Inches(4.5)),
    style_config=None,
    layout_config=None,
):
    """
    创建组合图（支持 P(n,2) 任意组合）
    
    Args:
        slide: 幻灯片对象
        df: 数据 DataFrame
        categories_col: 分类列名（X 轴）
        series_config: 系列配置列表
            [
                {"key": "销售额", "name": "销售额", "type": "bar", "axis": "primary"},
                {"key": "增长率", "name": "增长率", "type": "line", "axis": "secondary"},
                {"key": "市场份额", "name": "市场份额", "type": "line", "axis": "secondary"},
            ]
        position: 图表位置 (left, top)
        size: 图表大小 (width, height)
        style_config: 样式配置对象（可选，默认使用 DEFAULT_STYLE_CONFIG）
                     可以是 StyleConfig 实例，或 None 使用默认样式
        layout_config: 布局配置对象（可选）
                      可以是 ChartLayoutConfig 实例，包含图例、轴配置
        
    Returns:
        Chart 对象
        
    Examples:
        >>> # 示例 1: 使用默认样式和布局
        >>> chart = create_combo_chart(
        ...     slide=slide,
        ...     df=df,
        ...     categories_col="日期",
        ...     series_config=[
        ...         {"key": "销售额", "name": "销售额", "type": "bar", "axis": "primary"},
        ...         {"key": "增长率", "name": "增长率", "type": "line", "axis": "secondary"},
        ...     ]
        ... )
        
        >>> # 示例 2: 自定义样式 + 布局
        >>> from ppt_station.chart_builder.styles import StyleConfig
        >>> from ppt_station.chart_builder.layout import (
        ...     ChartLayoutConfig,
        ...     LegendConfig,
        ...     CategoryAxisConfig,
        ... )
        >>> 
        >>> # 样式配置
        >>> custom_style = StyleConfig(
        ...     color_scheme="dark_only",
        ...     line_width_pt=1.5,
        ...     marker_style="none",
        ... )
        >>> 
        >>> # 布局配置
        >>> custom_layout = ChartLayoutConfig(
        ...     legend_config=LegendConfig(position="bottom", font_size_pt=10),
        ...     category_axis_config=CategoryAxisConfig(
        ...         is_date_axis=True,
        ...         major_unit_days=7,  # 每周显示一个刻度
        ...         number_format="yyyy-mm-dd",
        ...     ),
        ... )
        >>> 
        >>> chart = create_combo_chart(
        ...     slide=slide,
        ...     df=df,
        ...     categories_col="日期",
        ...     series_config=[...],
        ...     style_config=custom_style,
        ...     layout_config=custom_layout
        ... )
    
    Supported Combinations:
        - type: 'bar', 'column', 'line', 'area' (散点图待实现)
        - axis: 'primary', 'secondary'
        - 任意 (type1, axis1) + (type2, axis2) 的组合
        - 支持主轴多种类型，次轴多种类型
        
    Notes:
        - 分类（X轴）在 Excel 中占用 A 列
        - 系列数据从 B 列开始
        - 支持超过 25 个系列（AA, AB, ...）
        - 左轴标签在左侧，右轴标签在右侧，不会重叠
        - 默认样式：无标记点、1pt 线宽、深浅色交替
        - 默认布局：图例在底部、横轴普通分类轴
    """
    if not series_config:
        raise ValueError("series_config 不能为空")
    
    # 1. 按 (type, axis) 分组（用于决定引导图表类型）
    plot_groups = _group_series(series_config)
    
    # 2. 创建引导图表（写入全部系列数据到嵌入 Excel）
    chart = _bootstrap_chart(
        slide, df, categories_col, series_config, position, size
    )
    
    # ⭐ 核心修复：修正嵌入的 Excel 工作表中的日期数据
    # 如果分类列是日期类型，需要将 Excel 工作表中的文本日期转换为真实的日期数值
    _fix_embedded_excel_dates(chart, df, categories_col)
    
    # 3. 使用构建器完成剩余工作（传递样式配置和布局配置）
    builder = ChartBuilder(
        chart, 
        df, 
        categories_col,
        style_config=style_config if style_config is not None else DEFAULT_STYLE_CONFIG,
        layout_config=layout_config
    )
    
    # 注意：引导图表已经创建了第一个系列，构建器会继续追加
    # 如果需要完全自定义，可以在 builder.clear_bootstrap_chart() 中清理
    
    return builder.build(series_config)


def _bootstrap_chart(
    slide: Slide,
    df: pd.DataFrame,
    categories_col: str,
    series_config: List[Dict],
    position: tuple,
    size: tuple,
):
    """
    创建引导图表（写入全部系列数据到嵌入 Excel）

    用途：
    - 激活 <c:plotArea>，使其可以通过 XML 访问
    - 创建初始的分类轴和值轴
    - 将所有系列数据写入嵌入 Excel（确保"编辑数据"不丢数据）
    - 图表 XML 结构后续由 ChartBuilder 重建

    Args:
        slide: 幻灯片对象
        df: 数据 DataFrame
        categories_col: 分类列名
        series_config: 全部系列配置列表
        position: (left, top)
        size: (width, height)

    Returns:
        Chart 对象
    """
    chart_data = CategoryChartData()

    # 设置分类（X轴）
    categories = df[categories_col].tolist()

    if pd.api.types.is_datetime64_any_dtype(df[categories_col]):
        categories_bootstrap = [cat.strftime("%Y-%m-%d") if hasattr(cat, 'strftime') else str(cat) for cat in categories]
    else:
        categories_bootstrap = categories

    chart_data.categories = categories_bootstrap

    # 添加全部系列数据（确保嵌入 Excel 包含所有列）
    for series_cfg in series_config:
        chart_data.add_series(
            series_cfg["name"],
            df[series_cfg["key"]].tolist()
        )

    # 使用第一个系列的类型决定引导图表类型
    chart_type = _get_chart_type(series_config[0].get("type", "bar"))

    # 创建图表
    left, top = position
    width, height = size
    graphic_frame = slide.shapes.add_chart(
        chart_type, left, top, width, height, chart_data
    )

    return graphic_frame.chart


def _get_chart_type(type_str: str) -> XL_CHART_TYPE:
    """将图表类型字符串转换为 XL_CHART_TYPE 枚举"""
    type_map = {
        "bar": XL_CHART_TYPE.COLUMN_CLUSTERED,
        "column": XL_CHART_TYPE.COLUMN_CLUSTERED,
        "line": XL_CHART_TYPE.LINE,
        "area": XL_CHART_TYPE.AREA,
    }
    return type_map.get(type_str.lower(), XL_CHART_TYPE.COLUMN_CLUSTERED)


def _group_series(series_config: List[Dict]) -> Dict[tuple, List[Dict]]:
    """按 (type, axis) 分组系列"""
    from collections import defaultdict
    groups = defaultdict(list)
    for cfg in series_config:
        key = (cfg.get("type", "bar"), cfg.get("axis", "primary"))
        groups[key].append(cfg)
    return dict(groups)


def _fix_embedded_excel_dates(chart, df: pd.DataFrame, categories_col: str):
    """
    修正嵌入的 Excel 工作表中的日期数据
    
    新方案：将日期格式化为字符串标签（如 "2024/01"）
    这样 PowerPoint 就会正确显示，而不会出现 1900 年问题
    
    Args:
        chart: python-pptx Chart 对象
        df: 数据 DataFrame
        categories_col: 分类列名
    """
    # 检查是否为日期类型
    if not pd.api.types.is_datetime64_any_dtype(df[categories_col]):
        print(f"  → 分类列不是日期类型，跳过 Excel 工作表修正")
        return  # 不是日期类型，无需修正
    
    print(f"\n🔧 修正嵌入的 Excel 工作表日期数据（转换为格式化字符串）...")
    
    try:
        from datetime import datetime
        from openpyxl import load_workbook
        import io
        
        # 获取嵌入的 Excel 数据
        chart_part = chart.part
        xlsx_part = chart_part.chart_workbook.xlsx_part
        
        print(f"  → 找到嵌入的 Excel 工作表")
        
        # 将 Excel blob 加载为 openpyxl workbook
        xlsx_stream = io.BytesIO(xlsx_part.blob)
        wb = load_workbook(xlsx_stream)
        ws = wb.active
        
        print(f"  → 工作表行数: {ws.max_row}, 列数: {ws.max_column}")
        
        # 获取日期数据
        categories = df[categories_col].tolist()
        
        print(f"  → 准备修正 {len(categories)} 个日期值")
        print(f"  → 第一个值: {categories[0]} (类型: {type(categories[0])})")
        
        # 修正 A 列（分类列）的数据 - 转换为格式化字符串
        # Excel 工作表的第一行是表头，数据从第二行开始
        fixed_count = 0
        for i, cat_value in enumerate(categories, start=2):
            if hasattr(cat_value, 'to_pydatetime'):
                cat_value = cat_value.to_pydatetime()
            
            if isinstance(cat_value, datetime):
                # ⭐ 将日期格式化为字符串 "yyyy/mm"（年份/月份）
                date_str = cat_value.strftime('%Y/%m')
                ws.cell(row=i, column=1).value = date_str
                # 不设置数字格式，保持为文本
                fixed_count += 1
        
        print(f"  → 已修正 {fixed_count} 个单元格")
        print(f"  → 示例：{categories[0].strftime('%Y/%m') if isinstance(categories[0], datetime) or hasattr(categories[0], 'strftime') else 'N/A'}")
        
        # 将修改后的 workbook 写回 blob
        output_stream = io.BytesIO()
        wb.save(output_stream)
        xlsx_part._blob = output_stream.getvalue()
        
        print(f"  ✅ 嵌入 Excel 工作表修正完成（{fixed_count} 个日期值转换为格式化字符串）")
        
    except Exception as e:
        print(f"  ⚠️ 修正嵌入 Excel 工作表失败: {e}")
        import traceback
        traceback.print_exc()


# ============================================================================
# 便捷函数：向后兼容
# ============================================================================

def create_dual_axis_chart(
    slide: Slide,
    df: pd.DataFrame,
    categories_col: str,
    bar_columns: List[str],
    bar_names: List[str],
    line_columns: List[str],
    line_names: List[str],
    position: tuple = (Inches(1), Inches(2)),
    size: tuple = (Inches(8), Inches(4.5)),
):
    """
    便捷函数：创建双轴组合图（柱状图 + 折线图）
    
    这是向后兼容的 API，与旧的 xml_chart_patcher 接口一致。
    
    Example:
        >>> create_dual_axis_chart(
        ...     slide=slide,
        ...     df=df,
        ...     categories_col="日期",
        ...     bar_columns=["销售额", "成本"],
        ...     bar_names=["销售额", "成本"],
        ...     line_columns=["利润率"],
        ...     line_names=["利润率"],
        ... )
    """
    # 构建统一的 series_config
    series_config = []
    
    # 主轴柱状图
    for col, name in zip(bar_columns, bar_names):
        series_config.append({
            "key": col,
            "name": name,
            "type": "bar",
            "axis": "primary"
        })
    
    # 次轴折线图
    for col, name in zip(line_columns, line_names):
        series_config.append({
            "key": col,
            "name": name,
            "type": "line",
            "axis": "secondary"
        })
    
    # 调用统一的 API
    return create_combo_chart(
        slide, df, categories_col, series_config, position, size
    )

