import datetime as dt
from fxhnt.adapters.orchestration.assets import build_bybit_sleeve_forward_nav, build_positioning_forward_nav
from fxhnt.adapters.persistence.forward_nav import ForwardNavRepo
from fxhnt.adapters.warehouse.timescale_feature_store import TimescaleFeatureStore


def _seed(store, days=40):
    import math
    for i in range(6):
        px, rows, sign = 100.0, [], (1.0 if i % 2 == 0 else -1.0)
        for d in range(days):
            px *= 1 + sign * 0.01 + 0.003 * math.cos(0.4 * d + i)
            rows.append((d * 86400, {"close": px, "funding": 0.001 * sign, "spot_close": px,
                                     "long_ratio": 0.5 + 0.1 * sign}))
        store.write_features(f"SYM{i:02d}USDT", rows)


def _seed_btc(store, days=40):
    import math
    px, rows = 100.0, []
    for d in range(days):
        px *= 1 + 0.001 * math.cos(0.3 * d)
        rows.append((d * 86400, {"close": px}))
    store.write_features("BTCUSDT", rows)


def test_generic_builder_books_a_single_sleeve_track(tmp_path):
    repo = ForwardNavRepo(f"sqlite:///{tmp_path/'c.db'}"); repo.migrate()
    store = TimescaleFeatureStore("sqlite://", table="bybit_features"); _seed(store)
    out = build_bybit_sleeve_forward_nav(repo, store, "xsfunding",
                                         today="1970-02-09", at=dt.datetime(2026, 1, 1), cost_bps=0.0)
    assert out["days"] >= 1 and "t0" in out
    store.close()


def test_generic_builder_threads_unlock_events_for_the_unlock_sleeve(monkeypatch, tmp_path):
    """Task 2 (Phase 0b): unlock migrates onto its own Bybit single-sleeve track, like xsfunding — reusing
    the SAME generic `build_bybit_sleeve_forward_nav` with `sleeve="unlock"`. Unlike xsfunding, the unlock
    sleeve is uncomputable without the injected DefiLlama-style calendar (`_unlock_series` returns {} with
    no events), so this locks that `unlock_events` actually reaches `BybitFourEdgeStrategy` — not just
    `sleeves=["unlock"]`."""
    import fxhnt.application.bybit_forward_track as bft_mod

    captured: dict = {}
    real_strategy = bft_mod.BybitFourEdgeStrategy

    def _capturing_strategy(store, **kwargs):
        captured.update(kwargs)
        return real_strategy(store, **kwargs)

    monkeypatch.setattr(bft_mod, "BybitFourEdgeStrategy", _capturing_strategy)

    repo = ForwardNavRepo(f"sqlite:///{tmp_path/'c.db'}"); repo.migrate()
    store = TimescaleFeatureStore("sqlite://", table="bybit_features")
    # 50 days (not the default 40): recompute_series filters to date >= t0 ("1970-02-09" = day 39), so the
    # cliff's pre-window (10 days before cliff_day) must straddle day 39 for any row to survive the filter.
    _seed(store, days=50)
    _seed_btc(store, days=50)   # UnlockShortRunner's long hedge leg reads the "BTCUSDT" market symbol
    events = [{"sym": "SYM00", "cliff_day": 42, "n": 5_000_000, "cat": "investor"}]

    out = build_bybit_sleeve_forward_nav(repo, store, "unlock", today="1970-02-09",
                                         at=dt.datetime(2026, 1, 1), cost_bps=0.0, unlock_events=events)

    assert captured.get("sleeves") == ["unlock"]
    assert captured.get("unlock_events") == events
    assert out["days"] >= 1 and "t0" in out
    store.close()
