"""
Report configuration data models for the universal data report generator.
Defines ReportConfig, MetricDef, PageDef, ThemeConfig, and related enums.
"""
from dataclasses import dataclass, field
from enum import Enum
from datetime import date
from typing import Optional


class PeriodType(str, Enum):
    DAILY = 'daily'
    WEEKLY = 'weekly'
    MONTHLY = 'monthly'
    QUARTERLY = 'quarterly'
    CUSTOM = 'custom'


class AudienceType(str, Enum):
    MANAGEMENT = 'management'
    OPERATION = 'operation'
    CLIENT = 'client'
    CUSTOM = 'custom'


class ComparisonType(str, Enum):
    PREV_PERIOD = 'prev_period'
    YOY = 'yoy'
    NONE = 'none'


class ColumnRole(str, Enum):
    TIME = 'time'
    NUMERIC = 'numeric'
    CATEGORY = 'category'
    TEXT = 'text'
    ID = 'id'
    BOOLEAN = 'boolean'
    UNKNOWN = 'unknown'


class AggregationType(str, Enum):
    SUM = 'sum'
    COUNT = 'count'
    AVG = 'avg'
    MAX = 'max'
    MIN = 'min'
    DISTINCT_COUNT = 'distinct_count'


class MetricType(str, Enum):
    KPI = 'kpi'
    TREND = 'trend'
    DISTRIBUTION = 'distribution'
    RANKING = 'ranking'
    FUNNEL = 'funnel'
    ALERT = 'alert'


class ChartType(str, Enum):
    COLUMN = 'column'
    BAR = 'bar'
    LINE = 'line'
    DOUGHNUT = 'doughnut'
    PIE = 'pie'
    FUNNEL = 'funnel'
    TABLE = 'table'
    GROUPED_BAR = 'grouped_bar'


class ThemePreset(str, Enum):
    BUSINESS_CLASSIC = 'business_classic'
    FRESH_SIMPLE = 'fresh_simple'
    DARK_PROFESSIONAL = 'dark_professional'
    WARM_BRAND = 'warm_brand'
    CUSTOM = 'custom'
    FROM_TEMPLATE = 'from_template'


@dataclass
class ColumnProfile:
    column_name: str
    dtype: str
    role: ColumnRole
    null_count: int
    null_rate: float
    unique_count: int
    sample_values: list = field(default_factory=list)
    numeric_stats: Optional[dict] = None
    inferred_label: str = ''


@dataclass
class MetricDef:
    name: str
    label: str
    column: str
    aggregation: AggregationType
    metric_type: MetricType = MetricType.KPI
    unit: str = ''
    format_spec: str = ',.0f'
    selected: bool = True
    is_primary: bool = False


@dataclass
class PageDef:
    page_id: str
    title: str
    page_type: str
    order: int
    selected: bool = True
    elements: list[dict] = field(default_factory=list)
    conclusion_title: str = ''


@dataclass
class ConfirmationSpec:
    """Six user confirmations required before building a report."""
    period_and_page_range: bool = False
    core_metrics: bool = False
    audience_and_decision: bool = False
    visual_style_and_palette: bool = False
    page_structure_and_template: bool = False
    data_scope_and_field_mapping: bool = False

    def missing_items(self) -> list[str]:
        labels = {
            'period_and_page_range': '报告周期与页数范围',
            'core_metrics': '核心指标集',
            'audience_and_decision': '受众与决策场景',
            'visual_style_and_palette': '视觉风格与配色方向',
            'page_structure_and_template': '页面结构与模板方案',
            'data_scope_and_field_mapping': '数据范围与字段映射',
        }
        return [
            label for field_name, label in labels.items()
            if not getattr(self, field_name)
        ]

    def is_complete(self) -> bool:
        return not self.missing_items()


@dataclass
class ThemeConfig:
    preset: ThemePreset = ThemePreset.BUSINESS_CLASSIC
    name: str = '商务经典'
    primary: str = '#1E3A5F'
    accent: str = '#10B981'
    accent_neg: str = '#EF4444'
    secondary: str = '#64748B'
    dark: str = '#1F3A5C'
    white: str = '#FFFFFF'
    gray_bg: str = '#F2F2F2'
    card_bg: str = '#E7F0F7'
    text: str = '#333333'
    text_gray: str = '#666666'
    line: str = '#D9D9D9'
    chart_series: list[str] = field(default_factory=lambda: [
        '#1E3A5F', '#10B981', '#ED7D31', '#64748B',
        '#EF4444', '#707070', '#4472C4', '#10B981'
    ])
    title_font: str = '微软雅黑'
    body_font: str = '微软雅黑'
    number_font: str = 'Arial'


@dataclass
class ReportConfig:
    title: str
    period_type: PeriodType
    date_range: tuple[date, date]
    period_str: str = ''

    metrics: list[MetricDef] = field(default_factory=list)
    pages: list[PageDef] = field(default_factory=list)

    audience: AudienceType = AudienceType.MANAGEMENT
    decision_scenario: str = ''
    custom_audience: str = ''

    theme: ThemeConfig = field(default_factory=ThemeConfig)
    template_path: str = ''
    template_profile: Optional[object] = None  # TemplateProfile from template_parser
    use_template_theme: bool = True
    visual_style_direction: str = ''
    page_structure_template: str = ''

    filters: dict = field(default_factory=dict)
    comparison: ComparisonType = ComparisonType.PREV_PERIOD
    page_count_range: tuple[int, int] = (6, 15)

    source_label: str = '数据报告系统'

    data_scope: str = ''
    data_field_mapping: dict = field(default_factory=dict)

    data_profiling: Optional[dict] = None
    agent_recommendations: Optional[dict] = None
    user_confirmation: ConfirmationSpec = field(default_factory=ConfirmationSpec)
    require_six_confirmations: bool = True

    quality_threshold: int = 85
    max_fix_iterations: int = 5

    def to_dict(self) -> dict:
        return {
            'title': self.title,
            'period_type': self.period_type.value,
            'period_str': self.period_str,
            'page_count_range': list(self.page_count_range),
            'audience': self.audience.value,
            'theme_preset': self.theme.preset.value,
            'metrics_count': len(self.metrics),
            'pages_count': len(self.pages),
            'six_confirmations_complete': self.user_confirmation.is_complete(),
        }


def validate_six_confirmations(config: ReportConfig, data_columns: Optional[list[str]] = None) -> list[str]:
    """Return validation gaps for the six confirmation contract."""
    issues = []

    missing = config.user_confirmation.missing_items()
    if missing:
        issues.append('六项确认未完成：' + '、'.join(missing))

    if not config.period_str and not config.date_range:
        issues.append('缺少报告周期。')
    if not config.page_count_range or len(config.page_count_range) != 2:
        issues.append('缺少页数范围。')
    if not [m for m in config.metrics if m.selected]:
        issues.append('缺少已确认的核心指标集。')
    if not config.decision_scenario:
        issues.append('缺少受众与决策场景说明。')
    if not config.visual_style_direction and not config.theme:
        issues.append('缺少视觉风格与配色方向。')
    if not config.pages:
        issues.append('缺少页面结构与模板方案。')
    if not config.data_field_mapping:
        issues.append('缺少数据范围与字段映射。')

    if data_columns:
        missing_cols = []
        for metric in config.metrics:
            if metric.selected and metric.column and metric.column not in data_columns:
                missing_cols.append(f'{metric.label} -> {metric.column}')
        if missing_cols:
            issues.append('核心指标字段映射不存在：' + '、'.join(missing_cols[:8]))

    selected_pages = [p for p in config.pages if p.selected]
    if config.page_count_range and selected_pages:
        low, high = config.page_count_range
        if len(selected_pages) < low - 1 or len(selected_pages) > high + 1:
            issues.append(f'页面数量 {len(selected_pages)} 不在确认范围 {low}-{high} 页附近。')

    return issues
