from dataclasses import dataclass
from typing import Tuple


# Canonical: Underlying Daily
@dataclass(frozen=True)
class CanonicalUnderlyingDaily:
    """
    One row per (symbol, date).
    """

    # must exist after alignment
    required_columns: Tuple[str, ...] = (
        "symbol",
        "date",
        "px_open",
        "px_high",
        "px_low",
        "px_close",
        "volume",
    )

    # may exist depending on data availability
    optional_columns: Tuple[str, ...] = (
        "bid",
        "ask",
        "mid",
        "call_open_int_tot",
        "put_open_int_tot",
        "vix",
        "rate_sofr_90d",
        "rate_usgg3m",
    )

    # logically defined volatility surfaces
    derived_columns: Tuple[str, ...] = (
        # ATM IV
        "iv_atm_hist",

        # IV surface (30D)
        "iv_30_m90",
        "iv_30_m95",
        "iv_30_m100",
        "iv_30_m105",
        "iv_30_m110",

        # IV surface (60D)
        "iv_60_m90",
        "iv_60_m95",
        "iv_60_m100",
        "iv_60_m105",
        "iv_60_m110",
    )

    @property
    def columns(self) -> Tuple[str, ...]:
        return (
            self.required_columns
            + self.optional_columns
            + self.derived_columns
        )



# Canonical: Option Chain Snapshot
@dataclass(frozen=True)
class CanonicalOptionChainSnapshot:
    """
    One row per option contract at a snapshot date.
    """

    required_columns: Tuple[str, ...] = (
        "symbol",
        "date",
        "expiration",
        "strike",
        "call_ticker",
        "put_ticker",
        "exercise_type",
        "contract_size",
        "periodicity",
    )

    # computed from underlying + chain
    derived_columns: Tuple[str, ...] = (
        "time_to_expiry",
        "moneyness",
        "log_moneyness",
    )

    @property
    def columns(self) -> Tuple[str, ...]:
        return self.required_columns + self.derived_columns



# Canonical: IV Surface Snapshot (delta-based)
@dataclass(frozen=True)
class CanonicalIVSurfaceSnapshot:
    """
    Delta-based IV surface for a single snapshot.
    """

    required_columns: Tuple[str, ...] = (
        "symbol",
        "date",
        "expiration",
        "delta",
        "strike",
        "iv",
    )

    optional_columns: Tuple[str, ...] = (
        "spot",
        "dividend",
    )

    @property
    def columns(self) -> Tuple[str, ...]:
        return self.required_columns + self.optional_columns



# Export helpers
CANONICAL_TABLES = {
    "underlying_daily": CanonicalUnderlyingDaily(),
    "option_chain_snapshot": CanonicalOptionChainSnapshot(),
    "iv_surface_snapshot": CanonicalIVSurfaceSnapshot(),
}
