from __future__ import annotations

from datetime import datetime, timedelta, timezone

import polars as pl
from fastapi.testclient import TestClient

from uforia.api.app import create_app
from uforia.api.settings import ApiSettings
from uforia.storage import DatasetName, DatasetStore


def test_api_exposes_options_dashboards_and_signals(tmp_path) -> None:
    store = DatasetStore(tmp_path)
    base = datetime(2026, 3, 1, 12, tzinfo=timezone.utc)
    store.write(
        DatasetName.OPTIONS_SURFACE_SNAPSHOT,
        pl.DataFrame(
            [
                {
                    "ts": base,
                    "date": base.date(),
                    "underlying": "BTC",
                    "source": "surface_monitor",
                    "tenor_bucket": "7d",
                    "moneyness_bucket": "atm",
                    "mean_mark_iv": 0.55,
                    "mean_mid": 0.03,
                    "mean_spread": 0.002,
                    "option_count": 10,
                    "open_interest": 1000.0,
                    "volume": 200.0,
                    "iv_change_1h": 0.01,
                    "iv_change_24h": 0.02,
                    "iv_change_7d": 0.03,
                    "quality_flag": "ok",
                }
            ]
        ),
    )
    store.write(
        DatasetName.OPTIONS_CARRY_SERIES,
        pl.DataFrame(
            [
                {
                    "ts": base,
                    "date": base.date(),
                    "underlying": "BTC",
                    "source": "carry_vrp",
                    "atm_iv_7d": 0.55,
                    "atm_iv_14d": 0.57,
                    "atm_iv_30d": 0.60,
                    "realized_vol_7d": 0.40,
                    "realized_vol_14d": 0.42,
                    "realized_vol_30d": 0.45,
                    "carry_spread_7d": 0.15,
                    "carry_spread_30d": 0.15,
                    "term_carry_7_30": -0.05,
                    "roll_down_carry": 0.02,
                    "carry_zscore": 1.2,
                    "carry_regime": "rich",
                    "quality_flag": "ok",
                }
            ]
        ),
    )
    store.write(
        DatasetName.OPTIONS_SIGNAL_SERIES,
        pl.DataFrame(
            [
                {
                    "ts": base,
                    "date": base.date(),
                    "underlying": "BTC",
                    "source": "options_composite",
                    "vol_carry_score": 1.2,
                    "skew_stress_score": 0.7,
                    "surface_dislocation_score": 0.3,
                    "cross_asset_vol_score": 0.1,
                    "funding_vol_context_score": 0.4,
                    "breakeven_gap_score": -0.2,
                    "term_structure_momentum_score": 0.6,
                    "surface_factor_score": 0.3,
                    "residual_surface_rv_score": -0.1,
                    "ml_carry_toxicity_score": 0.5,
                    "expiry_pin_score": 0.2,
                    "gamma_flip_score": -0.4,
                    "adaptive_hedge_score": 0.1,
                    "sessionality_score": 0.25,
                    "dispersion_score": 0.15,
                    "funding_skew_score": 0.45,
                    "vol_regime_score": -0.2,
                    "vol_carry_long_threshold": 1.0,
                    "vol_carry_short_threshold": -1.0,
                    "skew_stress_long_threshold": 1.0,
                    "skew_stress_short_threshold": -1.0,
                    "surface_dislocation_long_threshold": 1.0,
                    "surface_dislocation_short_threshold": -1.0,
                    "cross_asset_vol_long_threshold": 1.0,
                    "cross_asset_vol_short_threshold": -1.0,
                    "funding_vol_context_long_threshold": 1.0,
                    "funding_vol_context_short_threshold": -1.0,
                    "breakeven_gap_long_threshold": 1.0,
                    "breakeven_gap_short_threshold": -1.0,
                    "term_structure_momentum_long_threshold": 1.0,
                    "term_structure_momentum_short_threshold": -1.0,
                    "surface_factor_long_threshold": 1.0,
                    "surface_factor_short_threshold": -1.0,
                    "residual_surface_rv_long_threshold": 1.0,
                    "residual_surface_rv_short_threshold": -1.0,
                    "ml_carry_toxicity_long_threshold": 1.0,
                    "ml_carry_toxicity_short_threshold": -1.0,
                    "expiry_pin_long_threshold": 1.0,
                    "expiry_pin_short_threshold": -1.0,
                    "gamma_flip_long_threshold": 1.0,
                    "gamma_flip_short_threshold": -1.0,
                    "adaptive_hedge_long_threshold": 1.0,
                    "adaptive_hedge_short_threshold": -1.0,
                    "sessionality_long_threshold": 1.0,
                    "sessionality_short_threshold": -1.0,
                    "dispersion_long_threshold": 1.0,
                    "dispersion_short_threshold": -1.0,
                    "funding_skew_long_threshold": 1.0,
                    "funding_skew_short_threshold": -1.0,
                    "vol_regime_long_threshold": 1.0,
                    "vol_regime_short_threshold": -1.0,
                    "signal_state": "neutral",
                    "quality_flag": "ok",
                }
            ]
        ),
    )
    store.write(
        DatasetName.OPTIONS_RELATIVE_VALUE_SERIES,
        pl.DataFrame(
            [
                {
                    "ts": base,
                    "date": base.date(),
                    "pair_id": "BTC_ETH",
                    "source": "btc_eth",
                    "atm_iv_spread_7d": 0.05,
                    "atm_iv_spread_30d": 0.04,
                    "skew_spread_30d": -0.01,
                    "vvix_spread": 3.0,
                    "razor_spread": 0.2,
                    "carry_spread": 0.1,
                    "funding_spread": 0.01,
                    "spread_zscore": 1.1,
                    "relative_regime": "btc_rich",
                    "quality_flag": "ok",
                }
            ]
        ),
    )
    store.write(
        DatasetName.VOL_REGIME_TRANSITION_SERIES,
        pl.DataFrame(
            [
                {
                    "ts": base - timedelta(hours=1),
                    "date": (base - timedelta(hours=1)).date(),
                    "underlying": "BTC",
                    "source": "vol_regime_transitions",
                    "signal_state": "neutral",
                    "prior_state": "neutral",
                    "next_state_probability_long_vol_bias": 0.2,
                    "next_state_probability_neutral": 0.6,
                    "next_state_probability_short_vol_bias": 0.2,
                    "median_state_duration_hours": 4.0,
                    "quality_flag": "ok",
                },
                {
                    "ts": base,
                    "date": base.date(),
                    "underlying": "BTC",
                    "source": "vol_regime_transitions",
                    "signal_state": None,
                    "prior_state": None,
                    "next_state_probability_long_vol_bias": None,
                    "next_state_probability_neutral": None,
                    "next_state_probability_short_vol_bias": None,
                    "median_state_duration_hours": None,
                    "quality_flag": "insufficient_data",
                },
            ]
        ),
    )

    app = create_app(settings=ApiSettings(data_root=tmp_path), store=store)
    client = TestClient(app)

    dashboards = client.get("/api/v1/options/dashboards")
    surface_series = client.get("/api/v1/options/vol_surface/series", params={"underlying": "BTC"})
    options_signals = client.get("/api/v1/options/signals")
    carry_latest = client.get(
        "/api/v1/options/signals/vol_carry_score/latest",
        params={"underlying": "BTC"},
    )
    transitions_latest = client.get(
        "/api/v1/options/vol_regime_transitions/latest",
        params={"underlying": "BTC"},
    )

    assert dashboards.status_code == 200
    dashboard_ids = {item["id"] for item in dashboards.json()["data"]}
    assert {
        "vol_surface",
        "carry_vrp",
        "skew_crash_premium",
        "surface_dislocation",
        "cross_asset_rv",
        "positioning_flow",
        "vol_cone",
        "term_structure_momentum",
        "gamma_exposure",
        "funding_context",
        "straddle_breakeven",
        "vol_regime_transitions",
        "surface_factor_rv",
        "ml_carry_toxicity",
        "expiry_flow_map",
        "adaptive_hedging",
        "sessionality_clocks",
        "btc_eth_dispersion",
        "funding_basis_skew",
    } <= dashboard_ids
    assert surface_series.status_code == 200
    assert len(surface_series.json()["data"]["points"]) == 1
    assert options_signals.status_code == 200
    signal_ids = {item["id"] for item in options_signals.json()["data"]}
    assert {
        "vol_carry_score",
        "vol_regime_score",
        "funding_vol_context_score",
        "breakeven_gap_score",
        "term_structure_momentum_score",
        "surface_factor_score",
        "residual_surface_rv_score",
        "ml_carry_toxicity_score",
        "expiry_pin_score",
        "gamma_flip_score",
        "adaptive_hedge_score",
        "sessionality_score",
        "dispersion_score",
        "funding_skew_score",
    } <= signal_ids
    assert carry_latest.status_code == 200
    assert carry_latest.json()["data"]["latest_values"]["vol_carry_score"] == 1.2
    assert transitions_latest.status_code == 200
    assert transitions_latest.json()["data"]["latest_updated_at"] == base.isoformat().replace("+00:00", "Z")
    assert transitions_latest.json()["data"]["latest_quality"] == "insufficient_data"
