"""The cockpit is Bybit-only (Phase 0b Task 7a): the fund's crypto is 100% Bybit (Binance execution removed
in Tasks 5-6), so the cockpit's Binance venue surface — the paper venue toggle, the Binance paper book view,
and the sim's Binance-vs-Bybit "compare" view — is removed. This is the UI-layer removal only (Task 7b
deletes the now-unreferenced Binance data/research backends); this file asserts the cockpit renders ONLY the
Bybit venue and every route stays clean (200, no 500s) regardless of stale/bookmarked query params.
NO network — in-memory SQLite repos, seeded directly."""
from __future__ import annotations

import datetime as dt

from fastapi.testclient import TestClient

from fxhnt.adapters.persistence.forward_nav import ForwardNavRepo
from fxhnt.adapters.persistence.paper_repo import PaperRepo
from fxhnt.adapters.web.app import create_app
from fxhnt.application.paper_book import PaperBookService
from fxhnt.ports.live_price import FakeLivePrice


def _seeded_bybit_repo() -> PaperRepo:
    repo = PaperRepo("sqlite://")
    repo.migrate()
    PaperBookService(repo, capital=100_000.0).derive_and_persist(
        run_date="2026-06-24", sleeve_weights={"positioning": 1.0},
        symbol_weights_by_sleeve={"positioning": {"BTCUSDT": -0.01}},
        prices={"BTCUSDT": 50_000.0}, at=dt.datetime(2026, 6, 24, tzinfo=dt.UTC))
    return repo


def _client() -> TestClient:
    fwd = ForwardNavRepo("sqlite://")
    fwd.migrate()
    binance = PaperRepo("sqlite://")   # the sim's generic DB handle — empty, unused by any assertion here
    binance.migrate()
    return TestClient(create_app(fwd, paper_repo=binance,
                                 bybit_paper_repo=_seeded_bybit_repo(),
                                 bybit_live=FakeLivePrice({"BTCUSDT": 50_000.0})))


# --- /paper: no venue toggle, no Binance book, stray ?venue= is ignored -------------------------------

def test_paper_has_no_binance_pill_or_book() -> None:
    c = _client()
    r = c.get("/paper/crypto")
    assert r.status_code == 200
    assert "Binance" not in r.text
    assert 'href="/paper/crypto?venue=binance"' not in r.text
    assert 'href="/paper/crypto?venue=bybit"' not in r.text
    assert "Bybit 4-edge book" in r.text


def test_paper_venue_binance_query_param_degrades_to_bybit() -> None:
    c = _client()
    r = c.get("/paper/crypto?venue=binance")
    assert r.status_code == 200
    assert "Bybit 4-edge book" in r.text
    assert "Binance paper book" not in r.text
    assert "Binance" not in r.text


def test_paper_live_has_no_venue_param() -> None:
    c = _client()
    r = c.get("/paper/live")
    assert r.status_code == 200
    assert "Binance" not in r.text
    # the auto-refresh hx-get on /paper no longer carries a venue query string
    assert 'hx-get="/paper/live?venue=' not in c.get("/paper").text


# --- /paper/replay: no venue toggle, stray ?venue= is ignored ------------------------------------------

def test_replay_has_no_binance_toggle() -> None:
    c = _client()
    r = c.get("/paper/replay")
    assert r.status_code == 200
    assert "Binance" not in r.text
    assert "/paper/replay?venue=" not in r.text


def test_replay_venue_binance_query_param_degrades_to_bybit() -> None:
    # A stray `?venue=binance` is simply ignored — the (single) Bybit repo's replay renders, never a 500.
    c = _client()
    r = c.get("/paper/replay?venue=binance")
    assert r.status_code == 200
    assert "Binance" not in r.text


def test_replay_at_ignores_stray_venue_param() -> None:
    c = _client()
    r = c.get("/paper/replay/at?date=2026-06-24&venue=binance")
    assert r.status_code == 200


# --- /paper/sim: no binance_combined / compare book, no compare view -----------------------------------

def test_sim_has_no_binance_or_compare_book_option() -> None:
    c = _client()
    r = c.get("/paper/sim")
    assert r.status_code == 200
    assert "Binance" not in r.text
    assert "Compare A/B" not in r.text
    assert 'book=binance_combined' not in r.text
    assert 'book=compare' not in r.text


def test_sim_book_compare_degrades_to_default_not_the_compare_view() -> None:
    c = _client()
    r = c.get("/paper/sim", params={"book": "compare"})
    assert r.status_code == 200
    assert 'data-book="bybit_4edge"' in r.text
    assert "Compare A/B" not in r.text


def test_sim_run_book_compare_degrades_gracefully_never_the_compare_partial() -> None:
    c = _client()
    r = c.get("/paper/sim/run", params={"book": "compare", "capital": 100000})
    assert r.status_code == 200
    assert "no overlap" not in r.text.lower()          # the removed compare partial's language
    assert r.text.count("<polyline") < 2                # never the dual-overlay compare chart
    assert "Binance" not in r.text


def test_sim_run_book_binance_combined_degrades_gracefully() -> None:
    c = _client()
    r = c.get("/paper/sim/run", params={"book": "binance_combined", "capital": 100000})
    assert r.status_code == 200
    assert "Binance" not in r.text


# --- every cockpit route stays clean: 200, no 500, no binance/compare surface --------------------------

def test_all_cockpit_routes_render_200_bybit_only() -> None:
    c = _client()
    for path in ("/", "/paper", "/paper/sim", "/paper/replay", "/strategy/xsfunding"):
        r = c.get(path)
        assert r.status_code == 200, f"{path} returned {r.status_code}"
        assert "Binance" not in r.text, f"{path} still renders a Binance surface"
        assert "Compare A/B" not in r.text, f"{path} still renders the compare view"


def test_healthz_and_strategy_detail_unaffected() -> None:
    c = _client()
    assert c.get("/healthz").status_code == 200
    assert c.get("/strategy/xsfunding").status_code == 200
    assert c.get("/strategy/bybit_4edge").status_code == 200
