import datetime as dt

from typer.testing import CliRunner

from fxhnt.adapters.persistence.forward_nav import ForwardNavRepo
from fxhnt.application.backtest_refs import backtest_ref


class _Replay:
    def advance(self, last, extra):
        return [("2024-01-0%d" % i, 0.01) for i in range(1, 6)], {}


def test_backtest_ref_upserts_for_recompute_replay(tmp_path):
    repo = ForwardNavRepo(f"sqlite:///{tmp_path/'c.db'}")
    repo.migrate()
    sm = backtest_ref("multistrat", store=None, build_strategy=lambda: _Replay())
    assert sm is not None
    repo.upsert_backtest_summary(sm, at=dt.datetime(2024, 1, 6))
    # read it back via the SAME reader the gate provider uses (forward_ingest.py:48 → all_backtest_summaries())
    assert any(b.strategy_id == "multistrat" for b in repo.all_backtest_summaries())


class _FakeSettings:
    """Minimal settings stand-in — an in-memory sqlite DSN is enough for the plumbing exercised below (the
    bybit-book compute itself is stubbed out; only the CLI wiring is under test)."""
    operational_dsn = "sqlite://"
    paper_capital = 100_000.0


def test_bybit_commands_share_persist_bybit_book_helper(monkeypatch):
    """SINGLE-SOURCE-OF-TRUTH lock (Task 6 fix): both the on-demand `bybit-persist-sleeve-ret` command and
    the scheduled `backtest-refs --all` command must funnel through the SAME compute-once
    `_persist_bybit_book` helper — the fix that closed the Critical regression where `backtest-refs --all`
    replaced the retired sleeve-ret Job but dropped its `bybit_sleeve_ret` write. Spy on the shared helper
    and assert BOTH commands invoke it exactly once."""
    from fxhnt import cli as climod

    calls: list[dict] = []

    def fake_persist_bybit_book(settings, **kw):
        calls.append(kw)
        return 0, "stub"

    monkeypatch.setattr(climod, "_persist_bybit_book", fake_persist_bybit_book)
    monkeypatch.setattr(climod, "get_settings", lambda: _FakeSettings())
    monkeypatch.setattr("fxhnt.registry.STRATEGY_REGISTRY", {})  # no non-bybit report sids to sweep

    runner = CliRunner()
    res1 = runner.invoke(climod.app, ["bybit-persist-sleeve-ret"])
    assert res1.exit_code == 0, res1.output
    res2 = runner.invoke(climod.app, ["backtest-refs", "--all"])
    assert res2.exit_code == 0, res2.output

    assert len(calls) == 2, (
        f"_persist_bybit_book must be invoked by BOTH bybit-persist-sleeve-ret AND backtest-refs --all, "
        f"got {len(calls)} call(s): {calls}")
