"""
Lightweight dataclasses for TEI API responses.

These are *optional* — the client returns raw dicts. Use these when you want
attribute access or IDE help in notebooks.

    >>> from core.tei_client import TEIClient, TEIReport
    >>> raw = TEIClient().get_report("abc123")
    >>> report = TEIReport.from_dict(raw)
    >>> report.discount_rate
    0.10
"""

from __future__ import annotations

from dataclasses import dataclass, field
from decimal import Decimal
from typing import Any


def _as_float(value: Any, default: float = 0.0) -> float:
    """Coerce Decimal/str/None into float."""
    if value is None or value == "":
        return default
    if isinstance(value, Decimal):
        return float(value)
    try:
        return float(value)
    except (TypeError, ValueError):
        return default


@dataclass
class TEIReport:
    """A TEI report template (model definition)."""

    id: str  # public_id
    name: str
    vendor: str
    version: str
    description: str = ""
    analysis_period_years: int = 3
    discount_rate: float = 0.10
    status: str = "active"
    field_count: int = 0
    instance_count: int = 0
    created_at: str = ""
    updated_at: str = ""

    @classmethod
    def from_dict(cls, data: dict) -> TEIReport:
        return cls(
            id=str(data.get("id", "")),
            name=data.get("name", ""),
            vendor=data.get("vendor", ""),
            version=data.get("version", ""),
            description=data.get("description", "") or "",
            analysis_period_years=int(data.get("analysis_period_years") or 3),
            discount_rate=_as_float(data.get("discount_rate"), 0.10),
            status=data.get("status", "active"),
            field_count=int(data.get("field_count") or 0),
            instance_count=int(data.get("instance_count") or 0),
            created_at=data.get("created_at", "") or "",
            updated_at=data.get("updated_at", "") or "",
        )


@dataclass
class TEIField:
    """A field definition belonging to a TEI report template."""

    id: int
    table: str  # 'benefits' | 'costs'
    field_key: str
    label: str
    field_type: str  # currency | percentage | integer | decimal | text
    description: str = ""
    category: str = ""
    default_value: str = ""
    is_annual: bool = True
    risk_adjustment: float | None = None
    sort_order: int = 0
    is_required: bool = False
    source_notes: str = ""

    @classmethod
    def from_dict(cls, data: dict) -> TEIField:
        ra = data.get("risk_adjustment")
        return cls(
            id=int(data.get("id") or 0),
            table=data.get("table", "benefits"),
            field_key=data.get("field_key", ""),
            label=data.get("label", ""),
            field_type=data.get("field_type", "decimal"),
            description=data.get("description", "") or "",
            category=data.get("category", "") or "",
            default_value=data.get("default_value", "") or "",
            is_annual=bool(data.get("is_annual", True)),
            risk_adjustment=_as_float(ra) if ra is not None else None,
            sort_order=int(data.get("sort_order") or 0),
            is_required=bool(data.get("is_required", False)),
            source_notes=data.get("source_notes", "") or "",
        )


@dataclass
class TEIValue:
    """
    A field value for a specific TEI tool instance.

    The exact wire format is not fully pinned in the OpenAPI spec; we use
    the client's friendly value convention (see ``TEIClient.get_values``):

        - annual fields:     {field_key, year_values: {"1": ..., "2": ...},
                              risk_adjustment, notes}
        - non-annual scalar: {field_key, value, risk_adjustment, notes}
    """

    field_key: str
    year_values: dict[str, float] = field(default_factory=dict)
    value: float | None = None
    risk_adjustment: float | None = None
    notes: str = ""

    @classmethod
    def from_dict(cls, data: dict) -> TEIValue:
        ra = data.get("risk_adjustment")
        yv_raw = data.get("year_values") or {}
        year_values = {str(k): _as_float(v) for k, v in yv_raw.items()}
        v = data.get("value")
        return cls(
            field_key=data.get("field_key", ""),
            year_values=year_values,
            value=_as_float(v) if v is not None else None,
            risk_adjustment=_as_float(ra) if ra is not None else None,
            notes=data.get("notes", "") or "",
        )

    def to_dict(self) -> dict:
        out: dict[str, Any] = {"field_key": self.field_key}
        if self.year_values:
            out["year_values"] = self.year_values
        if self.value is not None:
            out["value"] = self.value
        if self.risk_adjustment is not None:
            out["risk_adjustment"] = self.risk_adjustment
        if self.notes:
            out["notes"] = self.notes
        return out


@dataclass
class TEISummary:
    """Calculated financial summary for a TEI tool instance."""

    npv: float = 0.0
    roi: float = 0.0
    payback_months: float | None = None
    discount_rate: float = 0.10
    analysis_years: int = 3
    total_benefits_nominal: float = 0.0
    total_benefits_risk_adjusted: float = 0.0
    total_benefits_pv: float = 0.0
    total_costs_nominal: float = 0.0
    total_costs_risk_adjusted: float = 0.0
    total_costs_pv: float = 0.0
    yearly_breakdown: list[dict] = field(default_factory=list)
    category_breakdown: list[dict] = field(default_factory=list)
    raw: dict = field(default_factory=dict)

    @classmethod
    def from_dict(cls, data: dict) -> TEISummary:
        return cls(
            npv=_as_float(data.get("npv")),
            roi=_as_float(data.get("roi")),
            payback_months=(
                _as_float(data.get("payback_months"))
                if data.get("payback_months") is not None
                else None
            ),
            discount_rate=_as_float(data.get("discount_rate"), 0.10),
            analysis_years=int(data.get("analysis_years") or 3),
            total_benefits_nominal=_as_float(data.get("total_benefits_nominal")),
            total_benefits_risk_adjusted=_as_float(
                data.get("total_benefits_risk_adjusted")
            ),
            total_benefits_pv=_as_float(data.get("total_benefits_pv")),
            total_costs_nominal=_as_float(data.get("total_costs_nominal")),
            total_costs_risk_adjusted=_as_float(data.get("total_costs_risk_adjusted")),
            total_costs_pv=_as_float(data.get("total_costs_pv")),
            yearly_breakdown=list(data.get("yearly_breakdown") or []),
            category_breakdown=list(data.get("category_breakdown") or []),
            raw=dict(data),
        )
