"""liquid_universe — the dominant de-artifacting fix: restrict the carry universe to symbols whose MEDIAN
trailing daily turnover clears a dollar-volume floor. MEDIAN (not mean) so a spiky thin coin is excluded.
NO network — in-memory SQLite store."""
from __future__ import annotations

from fxhnt.adapters.warehouse.timescale_feature_store import TimescaleFeatureStore
from fxhnt.application.bybit_liquidity import liquid_universe

_DAY = 86_400


def _seed_turnover(store: TimescaleFeatureStore, sym: str, by_day: dict[int, float]) -> None:
    # Carry universe membership comes from the close panel, so write a close too.
    store.write_features(sym, [(d * _DAY, {"close": 100.0, "turnover": t}) for d, t in by_day.items()])


def test_only_symbols_above_threshold_returned() -> None:
    store = TimescaleFeatureStore("sqlite://", table="bybit_features")
    _seed_turnover(store, "BIGUSDT", {d: 50_000_000.0 for d in range(10)})    # deep
    _seed_turnover(store, "SMALLUSDT", {d: 1_000_000.0 for d in range(10)})   # thin
    out = liquid_universe(store, min_dollar_vol=10_000_000.0, lookback_days=90)
    store.close()
    assert out == {"BIGUSDT"}


def test_median_not_mean_excludes_spiky_thin_coin() -> None:
    store = TimescaleFeatureStore("sqlite://", table="bybit_features")
    # SPIKY: 9 days of ~0 turnover + ONE 1e9 spike. Mean >> 10M, but MEDIAN ~0 → must be EXCLUDED.
    spiky = {d: 100.0 for d in range(9)}
    spiky[9] = 1_000_000_000.0
    _seed_turnover(store, "SPIKYUSDT", spiky)
    # DEEP: consistently above the floor → median above → INCLUDED.
    _seed_turnover(store, "DEEPUSDT", {d: 20_000_000.0 for d in range(10)})
    out = liquid_universe(store, min_dollar_vol=10_000_000.0, lookback_days=90)
    store.close()
    assert out == {"DEEPUSDT"}, "median must reject the spiky thin coin (mean would have admitted it)"


def test_lookback_window_only_counts_recent_days() -> None:
    store = TimescaleFeatureStore("sqlite://", table="bybit_features")
    # Deep long ago, dead recently: trailing-window median should be ~0 → excluded.
    by_day = {d: 50_000_000.0 for d in range(50)}          # days 0..49 deep
    by_day.update({d: 1.0 for d in range(50, 100)})        # days 50..99 dead
    _seed_turnover(store, "FADEDUSDT", by_day)
    out = liquid_universe(store, min_dollar_vol=10_000_000.0, lookback_days=30, as_of=99)
    store.close()
    assert out == set()


def test_empty_store_returns_empty() -> None:
    store = TimescaleFeatureStore("sqlite://", table="bybit_features")
    assert liquid_universe(store) == set()
    store.close()
