"""
绘图区 (Plot) XML 操作模块

负责创建不同类型的图表绘图区 (<c:barChart>, <c:lineChart> 等)。
"""

from lxml import etree
from typing import Literal

from ..oxml_ns import NAMESPACES

ChartType = Literal['bar', 'column', 'line', 'area', 'scatter']


def create_plot_element(
    plotArea,
    chart_type: ChartType,
    cat_ax_id: int,
    val_ax_id: int,
    order_index: int = 0,
):
    """
    创建图表绘图区元素
    
    Args:
        plotArea: 父绘图区元素
        chart_type: 图表类型 ('bar', 'line', 'area', 'scatter')
        cat_ax_id: 分类轴 ID
        val_ax_id: 值轴 ID
        order_index: 绘图顺序索引（0=最底层，越大越在上层）
        
    Returns:
        创建的绘图元素 (lxml Element)
        
    Raises:
        ValueError: 如果图表类型不支持
        
    Notes:
        - 每个绘图元素会自动关联指定的坐标轴
        - 调用方需要自己添加系列 (<c:ser>)
        - order_index 决定图表的堆叠顺序
    """
    chart_type = chart_type.lower()
    
    if chart_type in ('bar', 'column'):
        return _create_bar_plot(plotArea, cat_ax_id, val_ax_id, order_index)
    elif chart_type == 'line':
        return _create_line_plot(plotArea, cat_ax_id, val_ax_id, order_index)
    elif chart_type == 'area':
        return _create_area_plot(plotArea, cat_ax_id, val_ax_id, order_index)
    elif chart_type == 'scatter':
        return _create_scatter_plot(plotArea, cat_ax_id, val_ax_id, order_index)
    else:
        raise ValueError(f"不支持的图表类型: {chart_type}")


def _create_bar_plot(plotArea, cat_ax_id: int, val_ax_id: int, order_index: int):
    """创建柱状图元素"""
    barChart = etree.SubElement(plotArea, f"{{{NAMESPACES['c']}}}barChart")
    
    # barDir: 柱状图方向 ('col' = 垂直柱状, 'bar' = 水平条形)
    barDir = etree.SubElement(barChart, f"{{{NAMESPACES['c']}}}barDir")
    barDir.set('val', 'col')
    
    # grouping: 分组方式 ('clustered' = 簇状, 'stacked' = 堆叠)
    grouping = etree.SubElement(barChart, f"{{{NAMESPACES['c']}}}grouping")
    grouping.set('val', 'clustered')
    
    # varyColors: 是否每个系列使用不同颜色
    varyColors = etree.SubElement(barChart, f"{{{NAMESPACES['c']}}}varyColors")
    varyColors.set('val', '0')
    
    # ⭐ 绘图顺序（决定堆叠层次，数字越小越在底层）
    # OOXML 规范建议在 varyColors 之后添加
    # 注意：这里不是 <c:ser> 的 order，而是整个 plot 的渲染顺序
    # 但 PowerPoint 实际使用 XML 元素出现的顺序来决定堆叠
    # 所以这个标签主要是语义化，真正的顺序由 XML 元素在 plotArea 中的位置决定
    
    # ⚠️ 注意：不在这里添加轴引用！
    # 轴引用应该在所有系列之后添加，由调用方在添加完系列后调用 add_axis_refs()
    
    return barChart


def _create_line_plot(plotArea, cat_ax_id: int, val_ax_id: int, order_index: int):
    """创建折线图元素"""
    lineChart = etree.SubElement(plotArea, f"{{{NAMESPACES['c']}}}lineChart")
    
    # grouping: 分组方式 ('standard' = 标准)
    grouping = etree.SubElement(lineChart, f"{{{NAMESPACES['c']}}}grouping")
    grouping.set('val', 'standard')
    
    # varyColors: 是否每个系列使用不同颜色
    varyColors = etree.SubElement(lineChart, f"{{{NAMESPACES['c']}}}varyColors")
    varyColors.set('val', '0')
    
    # ⚠️ 注意：不在这里添加轴引用！
    # 轴引用应该在所有系列之后添加
    
    return lineChart


def _create_area_plot(plotArea, cat_ax_id: int, val_ax_id: int, order_index: int):
    """创建面积图元素"""
    areaChart = etree.SubElement(plotArea, f"{{{NAMESPACES['c']}}}areaChart")
    
    # grouping: 分组方式 ('standard' = 标准)
    grouping = etree.SubElement(areaChart, f"{{{NAMESPACES['c']}}}grouping")
    grouping.set('val', 'standard')
    
    # varyColors
    varyColors = etree.SubElement(areaChart, f"{{{NAMESPACES['c']}}}varyColors")
    varyColors.set('val', '0')
    
    # ⚠️ 注意：不在这里添加轴引用！
    
    return areaChart


def _create_scatter_plot(plotArea, cat_ax_id: int, val_ax_id: int, order_index: int):
    """创建散点图元素"""
    scatterChart = etree.SubElement(plotArea, f"{{{NAMESPACES['c']}}}scatterChart")
    
    # scatterStyle: 散点样式 ('lineMarker' = 带线和标记)
    scatterStyle = etree.SubElement(scatterChart, f"{{{NAMESPACES['c']}}}scatterStyle")
    scatterStyle.set('val', 'lineMarker')
    
    # varyColors
    varyColors = etree.SubElement(scatterChart, f"{{{NAMESPACES['c']}}}varyColors")
    varyColors.set('val', '0')
    
    # ⚠️ 注意：不在这里添加轴引用！
    
    return scatterChart


def add_axis_refs(plot_element, cat_ax_id: int, val_ax_id: int):
    """
    为绘图元素添加坐标轴引用（应该在所有系列之后调用）
    
    Args:
        plot_element: 绘图元素 (<c:barChart>, <c:lineChart> 等)
        cat_ax_id: 分类轴 ID
        val_ax_id: 值轴 ID
    """
    axId1 = etree.SubElement(plot_element, f"{{{NAMESPACES['c']}}}axId")
    axId1.set('val', str(cat_ax_id))
    
    axId2 = etree.SubElement(plot_element, f"{{{NAMESPACES['c']}}}axId")
    axId2.set('val', str(val_ax_id))


def add_plot_categories(plot_element, categories: list):
    """
    为绘图元素添加共享的分类数据（在所有系列之前调用）
    
    Args:
        plot_element: 绘图元素 (<c:barChart>, <c:lineChart> 等)
        categories: 分类列表（X轴数据）
        
    Notes:
        - 在 OOXML 规范中，<c:cat> 是图表级别的共享元素
        - 应该在添加任何 <c:ser> 系列之前调用
        - 所有系列共享同一组分类数据
        - ⭐ 自动检测日期类型，使用 numCache（数值缓存）而非 strCache
    """
    from datetime import datetime
    
    # ⭐ 检测是否为日期类型
    is_date_data = False
    if categories and isinstance(categories[0], (datetime, float)):
        # datetime 对象或浮点数（Excel 日期序列号）
        is_date_data = True
    
    cat = etree.SubElement(plot_element, f"{{{NAMESPACES['c']}}}cat")
    
    if is_date_data:
        # ⭐ 新方案：将日期格式化为字符串，使用 strRef + strCache
        # 这样 PowerPoint 就会将其作为文本标签显示，不会出现 1900 年问题
        strRef = etree.SubElement(cat, f"{{{NAMESPACES['c']}}}strRef")
        
        # f (公式引用)
        f_elem = etree.SubElement(strRef, f"{{{NAMESPACES['c']}}}f")
        f_elem.text = f"Sheet1!$A$2:$A${len(categories) + 1}"
        
        # strCache (字符串缓存)
        strCache = etree.SubElement(strRef, f"{{{NAMESPACES['c']}}}strCache")
        ptCount = etree.SubElement(strCache, f"{{{NAMESPACES['c']}}}ptCount")
        ptCount.set('val', str(len(categories)))
        
        # 添加每个分类点（格式化为字符串）
        for i, cat_value in enumerate(categories):
            pt = etree.SubElement(strCache, f"{{{NAMESPACES['c']}}}pt")
            pt.set('idx', str(i))
            v = etree.SubElement(pt, f"{{{NAMESPACES['c']}}}v")
            
            if isinstance(cat_value, datetime):
                # 格式化为 "yyyy/mm"（年份/月份）
                v.text = cat_value.strftime('%Y/%m')
            elif isinstance(cat_value, float):
                # 假设是 Excel 日期序列号，转换为日期字符串
                base_date = datetime(1899, 12, 30)
                from datetime import timedelta
                actual_date = base_date + timedelta(days=cat_value)
                v.text = actual_date.strftime('%Y/%m')
            else:
                v.text = str(cat_value)
    else:
        # ⭐ 使用 strRef + strCache（普通分类轴）
        strRef = etree.SubElement(cat, f"{{{NAMESPACES['c']}}}strRef")
        
        # f (公式引用)
        f_elem = etree.SubElement(strRef, f"{{{NAMESPACES['c']}}}f")
        f_elem.text = f"Sheet1!$A$2:$A${len(categories) + 1}"
        
        # strCache (字符串缓存)
        strCache = etree.SubElement(strRef, f"{{{NAMESPACES['c']}}}strCache")
        ptCount = etree.SubElement(strCache, f"{{{NAMESPACES['c']}}}ptCount")
        ptCount.set('val', str(len(categories)))
        
        # 添加每个分类点
        for i, cat_value in enumerate(categories):
            pt = etree.SubElement(strCache, f"{{{NAMESPACES['c']}}}pt")
            pt.set('idx', str(i))
            v = etree.SubElement(pt, f"{{{NAMESPACES['c']}}}v")
            v.text = str(cat_value)

