# tests/test_per_option_greeks_from_raw.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


def test_per_option_greeks_from_raw():
    """
    Per-option Greeks test using real Bloomberg-style raw CSVs.

    Verifies:
    - raw → normalized → aligned → enriched → Greeks
    - both calls and puts computed
    - Greeks columns exist
    - no crashes on real data

    Does NOT validate numerical accuracy.
    """

    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 daily
    # ------------------------------------------------------------------
    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"],
    )

    # Use last available row (snapshot semantics)
    underlying_row = (
        underlying_daily
        .sort("date")
        .tail(1)
        .to_dicts()[0]
    )

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

    # ------------------------------------------------------------------
    # Compute per-option Greeks
    # ------------------------------------------------------------------
    greeks = build_per_option_greeks(
        chain=chain_enriched,
        underlying_row=underlying_row,
        rate_field="rate_sofr_90d",
    )

    # ------------------------------------------------------------------
    # Assertions
    # ------------------------------------------------------------------
    assert not greeks.is_empty()

    # Calls & puts
    assert set(greeks["option_type"].unique()) == {"call", "put"}

    # Required columns
    required_cols = {
        "symbol",
        "date",
        "expiration",
        "option_type",
        "ticker",
        "strike",
        "days_to_expiry",
        "sigma",
        "price",
        "delta",
        "gamma",
        "vega",
        "theta",
        "charm",
        "vanna",
        "vomma",
        "contract_size",
    }
    assert required_cols.issubset(set(greeks.columns))

    # Sanity checks
    assert (greeks["days_to_expiry"] > 0).all()

    # Sigma column exists (may be NaN depending on surface availability)
    assert "sigma" in greeks.columns

    # Greeks computation ran (even if NaN)
    assert "price" in greeks.columns
    assert "delta" in greeks.columns
