# tests/test_exposure_features_from_greeks.py

from datetime import date

import polars as pl
import pytest

from ocf.data.normalize import (
    normalize_ohlcv,
    normalize_oi,
    normalize_ivol_30,
    normalize_ivol_60,
    normalize_sofr,
    normalize_usgg,
    normalize_vix,
    normalize_chain,
)
from ocf.data.align import align_underlying_daily
from ocf.data.enrich import enrich_option_chain_snapshot
from ocf.greeks.per_option import build_per_option_greeks
from ocf.greeks.exposure_curves import build_exposure_features


def test_exposure_features_from_real_greeks():
    """
    Exposure feature test using real Bloomberg-style raw data.

    Verifies:
    - per-option Greeks → exposure aggregation
    - output is flat, numeric, ML-ready
    - no crashes when sigma contains NaNs

    Does NOT validate numerical correctness.
    """

    raw_dir = "data/raw/bloomberg/spy"
    symbol = "SPY"
    snapshot_date = date(2024, 1, 19)

    # ------------------------------------------------------------------
    # Load raw CSVs
    # ------------------------------------------------------------------
    raw = {
        "ohlcv": pl.read_csv(f"{raw_dir}/ohlcv.csv"),
        "oi": pl.read_csv(f"{raw_dir}/oi.csv"),
        "iv30": pl.read_csv(f"{raw_dir}/ivol_30_mny.csv"),
        "iv60": pl.read_csv(f"{raw_dir}/ivol_60_mny.csv"),
        "sofr": pl.read_csv(f"{raw_dir}/riskfree_sofr.csv"),
        "usgg": pl.read_csv(f"{raw_dir}/riskfree_usgg.csv"),
        "vix": pl.read_csv(f"{raw_dir}/vix.csv"),
        "chain": pl.read_csv(f"{raw_dir}/chain.csv"),
    }

    # ------------------------------------------------------------------
    # Normalize
    # ------------------------------------------------------------------
    normalized = {
        "ohlcv": normalize_ohlcv(raw["ohlcv"], symbol),
        "oi": normalize_oi(raw["oi"], symbol),
        "iv30": normalize_ivol_30(raw["iv30"], symbol),
        "iv60": normalize_ivol_60(raw["iv60"], symbol),
        "sofr": normalize_sofr(raw["sofr"], symbol),
        "usgg": normalize_usgg(raw["usgg"], symbol),
        "vix": normalize_vix(raw["vix"], symbol),
        "chain": normalize_chain(
            raw["chain"],
            symbol=symbol,
            snapshot_date=snapshot_date,
        ),
    }

    # ------------------------------------------------------------------
    # Align underlying
    # ------------------------------------------------------------------
    underlying_daily = align_underlying_daily(
        symbol=symbol,
        ohlcv=normalized["ohlcv"],
        oi=normalized["oi"],
        iv30=normalized["iv30"],
        iv60=normalized["iv60"],
        sofr=normalized["sofr"],
        usgg=normalized["usgg"],
        vix=normalized["vix"],
    )

    underlying_row = (
        underlying_daily
        .sort("date")
        .tail(1)
        .to_dicts()[0]
    )

    # ------------------------------------------------------------------
    # Enrich chain + compute per-option Greeks
    # ------------------------------------------------------------------
    chain_enriched = enrich_option_chain_snapshot(
        chain=normalized["chain"],
        underlying_row=underlying_row,
    )

    greeks = build_per_option_greeks(
        chain=chain_enriched,
        underlying_row=underlying_row,
        rate_field="rate_sofr_90d",
    )

    assert not greeks.is_empty()

    # ------------------------------------------------------------------
    # Aggregate exposure features
    # ------------------------------------------------------------------
    exposure = build_exposure_features(
        greeks,
        atm_tau=0.15,
        slope_window=0.25,
    )

    # ------------------------------------------------------------------
    # Assertions
    # ------------------------------------------------------------------
    assert isinstance(exposure, dict)
    assert len(exposure) > 0

    # Core exposure keys must exist
    required_keys = {
        "delta_exposure_total",
        "gamma_exposure_total",
        "vega_exposure_total",
        "theta_exposure_total",
        "charm_exposure_total",
        "vanna_exposure_total",
        "vomma_exposure_total",
    }

    assert required_keys.issubset(set(exposure.keys()))

    # All values should be finite floats (or zero)
    for k, v in exposure.items():
        assert isinstance(v, float)