"""데이터 모델 정의"""
from dataclasses import dataclass, field
from decimal import Decimal
from datetime import date
from typing import Optional


@dataclass
class MonthlyValue:
    """월별 예산/실적 값"""
    month: str
    budget: Decimal = Decimal(0)
    actual: Decimal = Decimal(0)

    @property
    def variance(self) -> Decimal:
        """차이 (실적 - 예산)"""
        return self.actual - self.budget

    @property
    def achievement_rate(self) -> Optional[Decimal]:
        """달성률 (%)"""
        if self.budget == 0:
            return None
        return (self.actual / self.budget) * 100


@dataclass
class PLItem:
    """손익계산서 항목"""
    name: str
    level: int = 0  # 들여쓰기 레벨 (0=대분류, 1=중분류, 2=소분류)
    is_total: bool = False  # 합계 항목 여부
    monthly_values: list[MonthlyValue] = field(default_factory=list)

    @property
    def total_budget(self) -> Decimal:
        """예산 합계"""
        return sum((v.budget for v in self.monthly_values), Decimal(0))

    @property
    def total_actual(self) -> Decimal:
        """실적 합계"""
        return sum((v.actual for v in self.monthly_values), Decimal(0))

    @property
    def total_variance(self) -> Decimal:
        """차이 합계"""
        return self.total_actual - self.total_budget

    @property
    def total_achievement_rate(self) -> Optional[Decimal]:
        """전체 달성률"""
        if self.total_budget == 0:
            return None
        return (self.total_actual / self.total_budget) * 100


@dataclass
class KPICard:
    """KPI 카드"""
    title: str
    value: Decimal
    unit: str = "円"
    previous_value: Optional[Decimal] = None
    target_value: Optional[Decimal] = None
    trend: Optional[str] = None  # "up", "down", "flat"
    color: str = "#2563eb"  # 기본 파란색

    @property
    def formatted_value(self) -> str:
        """포맷된 값"""
        if self.unit == "%":
            return f"{self.value:.1f}%"
        return f"{self.value:,.0f}{self.unit}"

    @property
    def change_rate(self) -> Optional[Decimal]:
        """전기 대비 변화율"""
        if self.previous_value is None or self.previous_value == 0:
            return None
        return ((self.value - self.previous_value) / self.previous_value) * 100


@dataclass
class ChartData:
    """차트 데이터"""
    labels: list[str]
    datasets: list[dict] = field(default_factory=list)
    title: str = ""
    chart_type: str = "bar"  # bar, line, combo, radar, waterfall, donut


@dataclass
class CashFlowItem:
    """캐시플로우 항목"""
    name: str
    category: str  # "operating", "investing", "financing"
    monthly_values: list[MonthlyValue] = field(default_factory=list)


@dataclass
class FinancialRatio:
    """재무 비율"""
    name: str
    value: Decimal
    unit: str = "%"
    benchmark: Optional[Decimal] = None
    description: str = ""


@dataclass
class FinancialReport:
    """전체 재무 리포트 데이터"""
    company_name: str
    fiscal_year: str
    period: str
    target_month: str
    generated_at: date = field(default_factory=date.today)

    # KPI 데이터
    annual_kpis: list[KPICard] = field(default_factory=list)
    monthly_kpis: list[KPICard] = field(default_factory=list)

    # P/L 데이터
    pl_items: list[PLItem] = field(default_factory=list)

    # 캐시플로우 데이터
    cashflow_items: list[CashFlowItem] = field(default_factory=list)

    # 재무 비율
    financial_ratios: list[FinancialRatio] = field(default_factory=list)

    # 차트 데이터
    charts: dict[str, ChartData] = field(default_factory=dict)

    # 월별 라벨
    month_labels: list[str] = field(default_factory=list)

    def get_pl_item(self, name: str) -> Optional[PLItem]:
        """이름으로 P/L 항목 조회"""
        for item in self.pl_items:
            if item.name == name:
                return item
        return None

    def get_kpi(self, title: str) -> Optional[KPICard]:
        """타이틀로 KPI 조회"""
        for kpi in self.annual_kpis + self.monthly_kpis:
            if kpi.title == title:
                return kpi
        return None
