from __future__ import annotations

from datetime import datetime, timedelta, timezone

import polars as pl

from uforia.config import AppConfig, ModelingConfig
from uforia.signals import build_razor_series
from uforia.storage import DatasetName, DatasetStore


def test_build_razor_series_from_hourly_option_history(tmp_path) -> None:
    store = DatasetStore(tmp_path)
    start = datetime(2026, 3, 1, 0, tzinfo=timezone.utc)
    expiry = start + timedelta(days=7)
    option_rows = []
    surface_rows = []
    for hour in range(24 * 3):
        ts = start + timedelta(hours=hour)
        underlying_price = 100000.0 + (hour * 25.0)
        for option_type, base_mid, delta in (
            ("call", 1500.0 + hour * 2.5, 0.52),
            ("put", 1450.0 + hour * 1.5, -0.48),
        ):
            option_rows.append(
                {
                    "ts": ts,
                    "date": ts.date(),
                    "venue": "deribit",
                    "underlying": "BTC",
                    "expiry": expiry,
                    "instrument_name": f"BTC-08MAR26-100000-{option_type.upper()[0]}",
                    "option_type": option_type,
                    "strike": 100000.0,
                    "bid": base_mid,
                    "ask": base_mid,
                    "mark": base_mid,
                    "mid": base_mid,
                    "mark_iv": 0.6,
                    "delta": delta,
                    "gamma": 0.01,
                    "vega": 0.1,
                    "index_price": underlying_price,
                    "underlying_price": underlying_price,
                    "forward": underlying_price,
                    "interest_rate": 0.0,
                    "open_interest": 1.0,
                    "volume": 1.0,
                    "quote_age_ms": 1_000,
                    "quality_flag": "ok",
                }
            )
        surface_rows.append(
            {
                "ts": ts,
                "date": ts.date(),
                "underlying": "BTC",
                "source": "ssvi",
                "atm_iv_7d": 0.55 + (hour * 0.0005),
                "atm_iv_14d": 0.56,
                "atm_iv_30d": 0.57,
                "atm_iv_60d": 0.58,
                "rr_25_7d": -0.04,
                "rr_25_30d": -0.03,
                "bf_25_7d": 0.02,
                "bf_25_30d": 0.03,
                "term_slope_7_30": -0.02,
                "term_slope_30_60": -0.01,
                "fit_quality": 0.001,
                "coverage_ratio": 0.85,
                "maturity_violations": 0,
                "fit_validity_flag": "ok",
                "quality_flag": "ok",
            }
        )

    store.write(DatasetName.OPTION_CHAIN_SNAPSHOT, pl.DataFrame(option_rows))
    store.write(DatasetName.SURFACE_FEATURES, pl.DataFrame(surface_rows))

    frame = build_razor_series(
        store,
        start=start,
        end=start + timedelta(hours=(24 * 3) - 1),
        underlying="BTC",
        config=AppConfig(modeling=ModelingConfig(razor_zscore_lookback_days=1)),
    )

    assert not frame.is_empty()
    assert "razor_pnl" in frame.columns
    assert "razor_vrp" in frame.columns
    assert frame.filter(pl.col("trade_band").is_not_null()).height > 0


def test_build_razor_series_handles_missing_option_history(tmp_path) -> None:
    store = DatasetStore(tmp_path)
    start = datetime(2026, 3, 1, 0, tzinfo=timezone.utc)
    frame = build_razor_series(
        store,
        start=start,
        end=start + timedelta(hours=24),
        underlying="ETH",
    )
    assert frame.is_empty()
