from __future__ import annotations

from datetime import datetime, timedelta, timezone

import polars as pl
from typer.testing import CliRunner

from uforia import cli as cli_module
from uforia.cli import _merge_with_existing_vvix, app
from uforia.storage import DatasetName, DatasetStore


def test_merge_with_existing_vvix_preserves_existing_qvvix(tmp_path) -> None:
    store = DatasetStore(tmp_path)
    ts = datetime(2026, 3, 9, 14, tzinfo=timezone.utc)
    store.write(
        DatasetName.VVIX_SERIES,
        pl.DataFrame(
            [
                {
                    "ts": ts,
                    "date": ts.date(),
                    "underlying": "BTC",
                    "source": "dvol",
                    "vol_index_value": 57.0,
                    "rvvix_7d": None,
                    "rvvix_14d": None,
                    "rvvix_30d": None,
                    "qvvix_30d": 88.0,
                    "model_version": "qvvix-var-v1",
                    "quality_flag": "ok",
                }
            ]
        ),
    )
    incoming = pl.DataFrame(
        [
            {
                "ts": ts,
                "date": ts.date(),
                "underlying": "BTC",
                "source": "dvol",
                "vol_index_value": 57.0,
                "rvvix_7d": 101.0,
                "rvvix_14d": 99.0,
                "rvvix_30d": 97.0,
                "qvvix_30d": None,
                "model_version": "rvvix-v1",
                "quality_flag": "ok",
            }
        ]
    )

    merged = _merge_with_existing_vvix(store, incoming, source="dvol", underlying="BTC")

    assert merged.item(0, "rvvix_14d") == 99.0
    assert merged.item(0, "qvvix_30d") == 88.0


def test_merge_with_existing_vvix_preserves_existing_rvvix(tmp_path) -> None:
    store = DatasetStore(tmp_path)
    ts = datetime(2026, 3, 9, 14, tzinfo=timezone.utc)
    store.write(
        DatasetName.VVIX_SERIES,
        pl.DataFrame(
            [
                {
                    "ts": ts,
                    "date": ts.date(),
                    "underlying": "BTC",
                    "source": "dvol",
                    "vol_index_value": 57.0,
                    "rvvix_7d": 101.0,
                    "rvvix_14d": 99.0,
                    "rvvix_30d": 97.0,
                    "qvvix_30d": None,
                    "model_version": "rvvix-v1",
                    "quality_flag": "ok",
                }
            ]
        ),
    )
    incoming = pl.DataFrame(
        [
            {
                "ts": ts,
                "date": ts.date(),
                "underlying": "BTC",
                "source": "dvol",
                "vol_index_value": 57.0,
                "rvvix_7d": None,
                "rvvix_14d": None,
                "rvvix_30d": None,
                "qvvix_30d": 88.0,
                "model_version": "qvvix-var-v1",
                "quality_flag": "ok",
            }
        ]
    )

    merged = _merge_with_existing_vvix(store, incoming, source="dvol", underlying="BTC")

    assert merged.item(0, "rvvix_14d") == 99.0
    assert merged.item(0, "qvvix_30d") == 88.0


def test_merge_with_existing_vvix_sets_combined_model_version(tmp_path) -> None:
    store = DatasetStore(tmp_path)
    ts = datetime(2026, 3, 9, 14, tzinfo=timezone.utc)
    store.write(
        DatasetName.VVIX_SERIES,
        pl.DataFrame(
            [
                {
                    "ts": ts,
                    "date": ts.date(),
                    "underlying": "BTC",
                    "source": "dvol",
                    "vol_index_value": 57.0,
                    "rvvix_7d": 101.0,
                    "rvvix_14d": None,
                    "rvvix_30d": None,
                    "qvvix_30d": None,
                    "model_version": "rvvix-v1",
                    "quality_flag": "ok",
                }
            ]
        ),
    )
    incoming = pl.DataFrame(
        [
            {
                "ts": ts,
                "date": ts.date(),
                "underlying": "BTC",
                "source": "dvol",
                "vol_index_value": 57.0,
                "rvvix_7d": None,
                "rvvix_14d": None,
                "rvvix_30d": None,
                "qvvix_30d": 88.0,
                "model_version": "qvvix-ewma-v2",
                "quality_flag": "ok",
            }
        ]
    )

    merged = _merge_with_existing_vvix(store, incoming, source="dvol", underlying="BTC")

    assert merged.item(0, "model_version") == "rvvix-v1+qvvix-ewma-v2"


def test_build_qvvix_command_uses_latest_available_vol_index_point(tmp_path, monkeypatch) -> None:
    store = DatasetStore(tmp_path)
    base = datetime(2026, 3, 17, 0, tzinfo=timezone.utc)
    rows = []
    for offset in range(36):
        ts = base + timedelta(hours=offset)
        rows.append(
            {
                "ts": ts,
                "date": ts.date(),
                "underlying": "BTC",
                "source": "dvol",
                "value": 50.0 + (offset * 0.1),
                "quality_flag": "ok",
            }
        )
    store.write(DatasetName.VOL_INDEX_SERIES, pl.DataFrame(rows))
    monkeypatch.setattr(cli_module, "_store", lambda: store)

    runner = CliRunner()
    result = runner.invoke(
        app,
        [
            "build",
            "qvvix",
            "--underlying",
            "BTC",
            "--source",
            "dvol",
            "--ts",
            "2026-03-18T12:00:00Z",
        ],
    )

    assert result.exit_code == 0, result.stdout
    written = (
        store.read(DatasetName.VVIX_SERIES, filters={"underlying": "BTC", "source": "dvol"})
        .sort("ts")
        .tail(1)
    )
    assert written.item(0, "ts") == datetime(2026, 3, 18, 11, tzinfo=timezone.utc)
    assert written.item(0, "qvvix_30d") is not None
