"""End-to-end test del gate IV-RV adattivo + Vol-of-Vol guard via Repository.

Verifica che la nuova API distinct-days componga correttamente repository
helpers + ``compute_adaptive_threshold``.
"""

from __future__ import annotations

from datetime import UTC, datetime, timedelta
from decimal import Decimal

import pytest

from cerbero_bite.core.adaptive_threshold import compute_adaptive_threshold
from cerbero_bite.state.db import connect, run_migrations
from cerbero_bite.state.models import MarketSnapshotRecord
from cerbero_bite.state.repository import Repository


def _seed_history(
    conn,
    repo: Repository,
    asset: str,
    base: datetime,
    n_ticks: int,
    iv_rv_value: Decimal,
    dvol_value: Decimal,
) -> None:
    for i in range(n_ticks):
        repo.record_market_snapshot(
            conn,
            MarketSnapshotRecord(
                timestamp=base + timedelta(minutes=15 * i),
                asset=asset,
                spot=Decimal("2000"),
                dvol=dvol_value,
                realized_vol_30d=Decimal("48"),
                iv_minus_rv=iv_rv_value,
                funding_perp_annualized=Decimal("0"),
                funding_cross_annualized=Decimal("0"),
                dealer_net_gamma=Decimal("0"),
                gamma_flip_level=None,
                oi_delta_pct_4h=None,
                liquidation_long_risk="low",
                liquidation_short_risk="low",
                macro_days_to_event=None,
                fetch_ok=True,
                fetch_errors_json=None,
            ),
        )
    conn.commit()


@pytest.fixture
def db_30d(tmp_path):
    """30 giorni di storia con IV-RV bimodale: prima metà 1.0, seconda metà 5.0."""
    db_path = tmp_path / "e2e.sqlite"
    conn = connect(str(db_path))
    run_migrations(conn)
    repo = Repository()
    base = datetime(2026, 4, 1, 0, 0, tzinfo=UTC)
    _seed_history(conn, repo, "ETH", base, 1440, Decimal("1.0"), Decimal("50"))
    _seed_history(
        conn,
        repo,
        "ETH",
        base + timedelta(days=15),
        1440,
        Decimal("5.0"),
        Decimal("50"),
    )
    return conn, repo


def test_distinct_days_count_matches_calendar_days(db_30d) -> None:
    """30 giorni di calendario seedati → COUNT DISTINCT = 30."""
    conn, repo = db_30d
    n = repo.count_iv_rv_distinct_days(
        conn,
        asset="ETH",
        max_days=60,
        as_of=datetime(2026, 5, 1, 0, 0, tzinfo=UTC),
    )
    assert n == 30


def test_window_values_returned_for_full_history(db_30d) -> None:
    conn, repo = db_30d
    values = repo.iv_rv_values_for_window(
        conn,
        asset="ETH",
        window_days=60,
        as_of=datetime(2026, 5, 1, 0, 0, tzinfo=UTC),
    )
    assert len(values) == 2880
    # Bimodale: 1440 valori 1.0 e 1440 valori 5.0
    assert sum(1 for v in values if v == Decimal("1.0")) == 1440
    assert sum(1 for v in values if v == Decimal("5.0")) == 1440


def test_p25_of_bimodal_history_picks_low_regime(db_30d) -> None:
    """Comporre repository + adaptive_threshold come fa entry_cycle."""
    conn, repo = db_30d
    as_of = datetime(2026, 5, 1, 0, 0, tzinfo=UTC)
    n_days = repo.count_iv_rv_distinct_days(
        conn, asset="ETH", max_days=60, as_of=as_of
    )
    values = repo.iv_rv_values_for_window(
        conn, asset="ETH", window_days=60, as_of=as_of
    )
    threshold = compute_adaptive_threshold(
        history=values,
        n_days=n_days,
        percentile=Decimal("0.25"),
        absolute_floor=Decimal("0"),
    )
    # P25 di 2880 valori bimodali: 1440 ×1.0, 1440 ×5.0 → soglia = 1.0
    assert threshold == Decimal("1.0")


def test_dvol_lookback_within_tolerance(db_30d) -> None:
    conn, repo = db_30d
    base = datetime(2026, 4, 1, 0, 0, tzinfo=UTC)
    out = repo.dvol_lookback(conn, asset="ETH", reference=base + timedelta(hours=24))
    assert out == Decimal("50")


def test_dvol_lookback_returns_none_outside_tolerance(db_30d) -> None:
    conn, repo = db_30d
    out = repo.dvol_lookback(
        conn,
        asset="ETH",
        reference=datetime(2025, 1, 1, tzinfo=UTC),
        tolerance_minutes=15,
    )
    assert out is None
