"""
Pure-Python domain types shared by every calculation engine.

Deliberately dependency-free (dataclasses + stdlib only, no SQLAlchemy, no FastAPI) so the
engines are unit-testable in isolation and so the calculation core never depends on how data is
stored or transported. `app/models/` (ORM) and `app/schemas/` (API I/O) both convert to/from
these types at their boundary — the engines never see an ORM row or an HTTP request directly.
"""
from __future__ import annotations

from dataclasses import dataclass, field
from datetime import date
from enum import Enum
from typing import Optional


class DataQualityStatus(str, Enum):
    VERIFIED = "VERIFIED"
    CALCULATED = "CALCULATED"
    ESTIMATED = "ESTIMATED"
    ASSUMPTION = "ASSUMPTION"
    MISSING = "MISSING"
    STALE = "STALE"
    CONFLICTING = "CONFLICTING"


class Applicability(str, Enum):
    APPLICABLE = "APPLICABLE"
    LIMITED = "LIMITED"
    NOT_MEANINGFUL = "NOT_MEANINGFUL"
    INSUFFICIENT_DATA = "INSUFFICIENT_DATA"


class MarketCapBucket(str, Enum):
    LARGE = "LARGE"
    MID = "MID"
    SMALL = "SMALL"
    MICRO = "MICRO"


# Sentinel for "not meaningful" / "cannot compute" so callers never mistake it for 0.
NM = "N/M"


@dataclass(frozen=True)
class MetricResult:
    """The result of computing one metric for one security at one point in time."""

    key: str
    value: Optional[float]          # None when status is MISSING/NOT_MEANINGFUL/INSUFFICIENT_DATA
    status: DataQualityStatus
    applicability: Applicability
    formula_version: str
    inputs_used: dict = field(default_factory=dict)
    as_of: Optional[date] = None
    note: Optional[str] = None

    @property
    def is_meaningful(self) -> bool:
        return (
            self.value is not None
            and self.applicability in (Applicability.APPLICABLE, Applicability.LIMITED)
            and self.status not in (DataQualityStatus.MISSING,)
        )

    @property
    def display(self) -> str:
        if not self.is_meaningful:
            return NM
        return f"{self.value:.4f}"


@dataclass(frozen=True)
class LineItems:
    """
    Raw fundamental line items for ONE reporting period of ONE security.
    All monetary values in the security's reporting currency, absolute (not per-share) unless
    noted. `None` means genuinely missing/not disclosed — never coerced to 0 upstream.
    """

    security_id: str
    period_end: date
    period_type: str  # "FY" | "Q1".."Q4" | "TTM"
    filing_date: Optional[date]
    currency: str

    revenue: Optional[float] = None
    cogs: Optional[float] = None
    gross_profit: Optional[float] = None
    operating_income: Optional[float] = None
    ebit: Optional[float] = None
    ebitda: Optional[float] = None
    net_income: Optional[float] = None
    eps_diluted: Optional[float] = None
    tax_expense: Optional[float] = None
    pretax_income: Optional[float] = None
    interest_expense: Optional[float] = None

    cash_and_equivalents: Optional[float] = None
    short_term_investments: Optional[float] = None
    total_debt: Optional[float] = None
    short_term_debt: Optional[float] = None
    long_term_debt: Optional[float] = None
    lease_liabilities: Optional[float] = None
    total_assets: Optional[float] = None
    current_assets: Optional[float] = None
    current_liabilities: Optional[float] = None
    shareholders_equity: Optional[float] = None
    minority_interest: Optional[float] = None
    preferred_equity: Optional[float] = None
    goodwill: Optional[float] = None
    intangible_assets: Optional[float] = None

    shares_outstanding: Optional[float] = None
    diluted_shares: Optional[float] = None

    operating_cash_flow: Optional[float] = None
    capital_expenditure: Optional[float] = None  # stored positive (magnitude of spend)
    dividends_paid: Optional[float] = None       # positive magnitude
    buybacks: Optional[float] = None              # gross, positive magnitude
    stock_issuance: Optional[float] = None        # positive magnitude

    # Market data, joined in at valuation/metric time (not part of the filing itself)
    price: Optional[float] = None
    market_cap: Optional[float] = None
    beta: Optional[float] = None

    receivables: Optional[float] = None
    inventory: Optional[float] = None
    depreciation_and_amortization: Optional[float] = None
    stock_based_compensation: Optional[float] = None
    adjusted_net_income: Optional[float] = None


@dataclass(frozen=True)
class FinancialSnapshot:
    """
    Everything the metrics engine needs for one security at one calculation date:
    current period line items + enough trailing history for growth/CAGR/trend metrics,
    ordered most-recent-first.
    """

    security_id: str
    industry_id: str
    sector_id: str
    market_cap_bucket: Optional[MarketCapBucket]
    calculation_date: date
    current: LineItems
    history: list[LineItems] = field(default_factory=list)  # prior periods, most recent first
    forward_eps_estimate: Optional[float] = None
    forward_estimate_status: DataQualityStatus = DataQualityStatus.ESTIMATED
