"""
Multi-theme color and visual style manager for the universal data report generator.
"""
from pptx.dml.color import RGBColor
from report_config import ThemeConfig, ThemePreset


PRESETS = {
    ThemePreset.BUSINESS_CLASSIC: ThemeConfig(
        preset=ThemePreset.BUSINESS_CLASSIC,
        name='商务经典',
        primary='#1E3A5F',
        accent='#10B981',
        accent_neg='#EF4444',
        secondary='#64748B',
        dark='#1F3A5C',
        white='#FFFFFF',
        gray_bg='#F2F2F2',
        card_bg='#E7F0F7',
        text='#333333',
        text_gray='#666666',
        line='#D9D9D9',
        chart_series=[
            '#1E3A5F', '#10B981', '#ED7D31', '#64748B',
            '#EF4444', '#707070', '#4472C4', '#5B9BD5',
        ],
    ),
    ThemePreset.FRESH_SIMPLE: ThemeConfig(
        preset=ThemePreset.FRESH_SIMPLE,
        name='清新简约',
        primary='#1B8A5E',
        accent='#10B981',
        accent_neg='#EF4444',
        secondary='#94A3B8',
        dark='#0F5C3B',
        white='#FFFFFF',
        gray_bg='#F8FAFC',
        card_bg='#ECFDF5',
        text='#1E293B',
        text_gray='#64748B',
        line='#E2E8F0',
        chart_series=[
            '#1B8A5E', '#3B82F6', '#F59E0B', '#94A3B8',
            '#EF4444', '#8B5CF6', '#06B6D4', '#10B981',
        ],
    ),
    ThemePreset.DARK_PROFESSIONAL: ThemeConfig(
        preset=ThemePreset.DARK_PROFESSIONAL,
        name='深色专业',
        primary='#1E293B',
        accent='#38BDF8',
        accent_neg='#F87171',
        secondary='#94A3B8',
        dark='#0F172A',
        white='#FFFFFF',
        gray_bg='#F1F5F9',
        card_bg='#E2E8F0',
        text='#1E293B',
        text_gray='#475569',
        line='#CBD5E1',
        chart_series=[
            '#1E293B', '#38BDF8', '#F59E0B', '#94A3B8',
            '#F87171', '#A78BFA', '#34D399', '#FB923C',
        ],
    ),
    ThemePreset.WARM_BRAND: ThemeConfig(
        preset=ThemePreset.WARM_BRAND,
        name='温暖品牌',
        primary='#C2410C',
        accent='#F97316',
        accent_neg='#DC2626',
        secondary='#78716C',
        dark='#7C2D12',
        white='#FFFFFF',
        gray_bg='#FFFBEB',
        card_bg='#FFF7ED',
        text='#292524',
        text_gray='#78716C',
        line='#D6D3D1',
        chart_series=[
            '#C2410C', '#F97316', '#EAB308', '#78716C',
            '#DC2626', '#84CC16', '#06B6D4', '#A855F7',
        ],
    ),
}


def get_theme(preset: ThemePreset, custom_overrides: dict = None) -> ThemeConfig:
    if preset == ThemePreset.CUSTOM:
        config = ThemeConfig(preset=ThemePreset.CUSTOM, name='自定义主题')
        if custom_overrides:
            for k, v in custom_overrides.items():
                if hasattr(config, k):
                    setattr(config, k, v)
        return config
    return PRESETS.get(preset, PRESETS[ThemePreset.BUSINESS_CLASSIC])


def extract_theme_from_template(template_profile) -> ThemeConfig:
    """
    Build a ThemeConfig from a TemplateProfile's detected colors and fonts.
    Adapts to dark templates by ensuring sufficient contrast for charts and text.
    Falls back to BUSINESS_CLASSIC if no usable colors were detected.
    """
    detected = getattr(template_profile, 'detected_theme', {}) or {}
    detected_fonts = getattr(template_profile, 'detected_fonts', {}) or {}
    if not detected:
        return PRESETS[ThemePreset.BUSINESS_CLASSIC].copy()

    def _get(key: str, fallback: str) -> str:
        return detected.get(key, detected.get(key.replace('_', ''), fallback))

    primary = _get('primary', '#1E3A5F')
    accent = _get('accent', '#10B981')
    accent_neg = _get('accent_neg', '#EF4444')
    text = _get('text', '#333333')
    text_gray = _get('text_gray', '#666666')
    bg = detected.get('background', '')

    # Detect if template is dark-themed
    is_dark = _is_dark_color(primary) or _is_dark_color(bg) or _is_dark_color(detected.get('dark', ''))

    if is_dark:
        # For dark templates: use bright, high-contrast colors
        primary = '#38BDF8' if _is_dark_color(primary) else primary  # bright cyan-blue
        text = '#F8FAFC' if _is_dark_color(text) else text  # near-white
        text_gray = '#94A3B8' if _is_dark_color(text_gray) else text_gray  # light slate
        card_bg = '#1E293B'  # dark slate card background
        gray_bg = '#0F172A'  # very dark background
        line = '#334155'  # medium slate line
        series = ['#38BDF8', '#34D399', '#FBBF24', '#F87171', '#A78BFA', '#22D3EE', '#FB923C', '#60A5FA']
    else:
        # Light template: derive soft backgrounds from primary
        card_bg = _lighten_hex(primary, 0.92)
        gray_bg = _lighten_hex(primary, 0.96)
        line = _lighten_hex(text, 0.80)
        series = [primary, accent, accent_neg]
        if 'accent2' in detected:
            series.append(detected['accent2'])
        else:
            series.append('#ED7D31')
        series.extend(['#64748B', '#EF4444', '#707070', '#4472C4'])
        series = series[:8]

    return ThemeConfig(
        preset=ThemePreset.FROM_TEMPLATE,
        name='模板提取主题',
        primary=primary,
        accent=accent,
        accent_neg=accent_neg,
        secondary=_get('secondary', '#64748B'),
        dark=_get('dark', primary),
        white='#FFFFFF',
        gray_bg=gray_bg,
        card_bg=card_bg,
        text=text,
        text_gray=text_gray,
        line=line,
        chart_series=series,
        title_font=detected_fonts.get('title_font', '微软雅黑'),
        body_font=detected_fonts.get('body_font', '微软雅黑'),
        number_font=detected_fonts.get('number_font', 'Arial'),
    )


def _is_dark_color(hex_str: str) -> bool:
    """Check if a hex color is dark (luminance < 120)."""
    if not hex_str or not isinstance(hex_str, str):
        return False
    hex_str = hex_str.lstrip('#')
    if len(hex_str) != 6:
        return False
    try:
        r = int(hex_str[0:2], 16)
        g = int(hex_str[2:4], 16)
        b = int(hex_str[4:6], 16)
        luminance = 0.299 * r + 0.587 * g + 0.114 * b
        return luminance < 120
    except Exception:
        return False


def _lighten_hex(hex_str: str, factor: float) -> str:
    """Lighten a hex color by mixing with white. factor 0=original, 1=white."""
    hex_str = hex_str.lstrip('#')
    if len(hex_str) != 6:
        return '#F2F2F2'
    try:
        r = int(int(hex_str[0:2], 16) * (1 - factor) + 255 * factor)
        g = int(int(hex_str[2:4], 16) * (1 - factor) + 255 * factor)
        b = int(int(hex_str[4:6], 16) * (1 - factor) + 255 * factor)
        return f'#{min(255, r):02X}{min(255, g):02X}{min(255, b):02X}'
    except Exception:
        return '#F2F2F2'


def merge_theme(template_theme: ThemeConfig, user_theme: ThemeConfig) -> ThemeConfig:
    """Merge two ThemeConfigs, with user_theme overriding non-empty values."""
    from dataclasses import fields
    result = ThemeConfig()
    for f in fields(ThemeConfig):
        user_val = getattr(user_theme, f.name, None)
        template_val = getattr(template_theme, f.name, None)
        if user_val is not None and user_val != '' and user_val != f.default:
            setattr(result, f.name, user_val)
        elif template_val is not None and template_val != '' and template_val != f.default:
            setattr(result, f.name, template_val)
    return result


def theme_to_rgb_colors(theme: ThemeConfig) -> dict:
    return {
        'primary': _hex_to_rgb(theme.primary),
        'accent': _hex_to_rgb(theme.accent),
        'accent_neg': _hex_to_rgb(theme.accent_neg),
        'secondary': _hex_to_rgb(theme.secondary),
        'dark': _hex_to_rgb(theme.dark),
        'white': _hex_to_rgb(theme.white),
        'gray_bg': _hex_to_rgb(theme.gray_bg),
        'card_bg': _hex_to_rgb(theme.card_bg),
        'text': _hex_to_rgb(theme.text),
        'text_gray': _hex_to_rgb(theme.text_gray),
        'line': _hex_to_rgb(theme.line),
        'green': _hex_to_rgb(theme.accent),
        'red': _hex_to_rgb(theme.accent_neg),
        'orange': _hex_to_rgb(theme.chart_series[2]) if len(theme.chart_series) > 2 else RGBColor(0xED, 0x7D, 0x31),
        'series': [_hex_to_rgb(c) for c in theme.chart_series],
    }


def _hex_to_rgb(hex_str: str) -> RGBColor:
    hex_str = hex_str.lstrip('#')
    if len(hex_str) == 6:
        return RGBColor(int(hex_str[0:2], 16), int(hex_str[2:4], 16), int(hex_str[4:6], 16))
    return RGBColor(0x33, 0x33, 0x33)


def list_themes() -> list[dict]:
    result = []
    for preset, config in PRESETS.items():
        result.append({
            'key': preset.value,
            'name': config.name,
            'primary': config.primary,
            'accent': config.accent,
        })
    result.append({
        'key': 'custom',
        'name': '自定义主题',
        'primary': '自定义',
        'accent': '自定义',
    })
    return result


if __name__ == '__main__':
    for t in list_themes():
        print(f"{t['key']}: {t['name']} (primary={t['primary']}, accent={t['accent']})")