"""BybitTestnetRepo (design §4.4): nav + fills tables for the testnet real-paper leg. In-memory SQLite
(no Postgres) like the other cockpit repo tests. Covers upsert+read nav, insert+read fills, and the per-day
`testnet_executed_on` idempotency marker."""
from __future__ import annotations

import datetime as dt

from sqlalchemy import inspect

from fxhnt.adapters.persistence.bybit_testnet_repo import (
    BybitTestnetRepo,
    TestnetFill,
    TestnetNav,
)

_AT = dt.datetime(2026, 6, 28, 0, 30, tzinfo=dt.UTC)


def _repo() -> BybitTestnetRepo:
    repo = BybitTestnetRepo("sqlite://")
    repo.migrate()
    return repo


def test_migrate_creates_tables() -> None:
    tables = set(inspect(_repo()._engine).get_table_names())
    assert {"bybit_testnet_nav", "bybit_testnet_fills"} <= tables


def test_upsert_and_read_nav() -> None:
    repo = _repo()
    repo.upsert_testnet_nav("2026-06-28", equity=10_000.0, realized_pnl=12.5, gross=0.8,
                            n_orders=3, mean_exec_slippage_bps=4.0, mean_timing_drift_bps=-1.0, ts=_AT)
    rows = repo.read_testnet_nav()
    assert rows == [TestnetNav(run_date="2026-06-28", equity=10_000.0, realized_pnl=12.5, gross=0.8,
                               n_orders=3, mean_exec_slippage_bps=4.0, mean_timing_drift_bps=-1.0)]


def test_upsert_nav_is_idempotent_per_date() -> None:
    repo = _repo()
    repo.upsert_testnet_nav("2026-06-28", equity=10_000.0, realized_pnl=0.0, gross=0.5,
                            n_orders=1, mean_exec_slippage_bps=1.0, mean_timing_drift_bps=0.0, ts=_AT)
    repo.upsert_testnet_nav("2026-06-28", equity=10_500.0, realized_pnl=5.0, gross=0.6,
                            n_orders=2, mean_exec_slippage_bps=2.0, mean_timing_drift_bps=0.5, ts=_AT)
    rows = repo.read_testnet_nav()
    assert len(rows) == 1 and rows[0].equity == 10_500.0 and rows[0].n_orders == 2


def test_read_nav_ascending() -> None:
    repo = _repo()
    for d, eq in (("2026-06-29", 2.0), ("2026-06-28", 1.0)):
        repo.upsert_testnet_nav(d, equity=eq, realized_pnl=0.0, gross=0.0, n_orders=0,
                                mean_exec_slippage_bps=0.0, mean_timing_drift_bps=0.0, ts=_AT)
    assert [r.run_date for r in repo.read_testnet_nav()] == ["2026-06-28", "2026-06-29"]


def _fill(symbol: str = "BTCUSDT", **kw: object) -> TestnetFill:
    base = dict(run_date="2026-06-28", symbol=symbol, side="BUY", qty=0.5, fill_price=100.5,
                mid_at_order=100.0, book_mark=99.0, exec_slippage_bps=50.0, timing_drift_bps=100.0,
                assumed_tier_bps=8.0, slippage_delta_bps=42.0, low_confidence=False, fee=0.07,
                order_id="ord-1", ts=_AT)
    base.update(kw)
    return TestnetFill(**base)  # type: ignore[arg-type]


def test_insert_and_read_fills() -> None:
    repo = _repo()
    repo.insert_testnet_fills([_fill("BTCUSDT"), _fill("ETHUSDT", side="SELL", qty=2.0)])
    rows = repo.read_testnet_fills("2026-06-28")
    assert {r.symbol for r in rows} == {"BTCUSDT", "ETHUSDT"}
    btc = next(r for r in rows if r.symbol == "BTCUSDT")
    assert btc.slippage_delta_bps == 42.0 and btc.order_id == "ord-1"


def test_read_fills_scoped_by_run_date() -> None:
    repo = _repo()
    repo.insert_testnet_fills([_fill(run_date="2026-06-28"), _fill(run_date="2026-06-29")])
    assert len(repo.read_testnet_fills("2026-06-28")) == 1


def test_fills_tolerate_low_confidence_nulls() -> None:
    repo = _repo()
    repo.insert_testnet_fills([_fill(mid_at_order=None, book_mark=None, exec_slippage_bps=None,
                                     timing_drift_bps=None, slippage_delta_bps=None, low_confidence=True)])
    row = repo.read_testnet_fills("2026-06-28")[0]
    assert row.low_confidence is True and row.mid_at_order is None and row.slippage_delta_bps is None


def test_executed_on_marker() -> None:
    repo = _repo()
    assert repo.testnet_executed_on("2026-06-28") is False
    repo.upsert_testnet_nav("2026-06-28", equity=10_000.0, realized_pnl=0.0, gross=0.0, n_orders=0,
                            mean_exec_slippage_bps=0.0, mean_timing_drift_bps=0.0, ts=_AT)
    assert repo.testnet_executed_on("2026-06-28") is True
    assert repo.testnet_executed_on("2026-06-29") is False


def test_latest_testnet_nav_returns_most_recent_row() -> None:
    repo = _repo()
    assert repo.latest_testnet_nav() is None
    repo.upsert_testnet_nav("2026-06-28", equity=10_000.0, realized_pnl=12.5, gross=0.8,
                            n_orders=3, mean_exec_slippage_bps=4.0, mean_timing_drift_bps=-1.0, ts=_AT)
    repo.upsert_testnet_nav("2026-06-29", equity=10_500.0, realized_pnl=25.0, gross=0.9,
                            n_orders=5, mean_exec_slippage_bps=5.0, mean_timing_drift_bps=0.5, ts=_AT)
    latest = repo.latest_testnet_nav()
    assert latest is not None and latest.run_date == "2026-06-29"
