from __future__ import annotations

import json
import os
from pathlib import Path

from dashboard import build_dashboard_snapshot, render_dashboard_html


def test_dashboard_snapshot_reads_bots_journals_and_reports(tmp_path: Path) -> None:
    runtime = tmp_path / "state"
    exp = runtime / "experiments" / "candidate_v63_loose_fast_decay"
    journal_dir = exp / "Tradeanalyse"
    journal_dir.mkdir(parents=True)
    (exp / "bot.pid").write_text("999999", encoding="utf-8")
    (exp / "bot.log").write_text("started\nScanne 6 Coins\n", encoding="utf-8")
    (journal_dir / "trade_journal.jsonl").write_text(
        json.dumps({"event": "entry", "coin": "WLD"}) + "\n" + json.dumps({"event": "exit", "coin": "WLD", "realized_pnl_usd": 0.42}) + "\n",
        encoding="utf-8",
    )
    reports = runtime / "reports"
    reports.mkdir()
    (reports / "historical_replay_report.txt").write_text("Historical Replay Tournament\n1. candidate", encoding="utf-8")
    (journal_dir / "near_miss.jsonl").write_text(json.dumps({"coin": "WLD", "drop_pct": -3.2, "distance_pct": 1.3, "reason": "no_flash_crash", "required_drop_pct": 4.5}) + "\n", encoding="utf-8")

    snapshot = build_dashboard_snapshot(runtime_dir=runtime)

    assert snapshot.live_orders_enabled is False
    assert snapshot.paper_bots[0].strategy_id == "candidate_v63_loose_fast_decay"
    assert snapshot.paper_bots[0].journal_events == 2
    assert snapshot.paper_bots[0].closed_trades == 1
    assert snapshot.paper_bots[0].scorecard.status == "Research"
    assert snapshot.paper_bots[0].scorecard.sample_size == 1
    assert snapshot.paper_bots[0].scorecard.total_pnl_usd == 0.42
    assert snapshot.paper_bots[0].near_miss_events == 1
    assert snapshot.paper_bots[0].open_position_count == 0
    assert snapshot.paper_bots[0].near_misses[0]["coin"] == "WLD"
    assert snapshot.paper_bots[0].near_misses[0]["distance_pct"] == 1.3
    assert "historical_replay_report" in snapshot.reports


def test_dashboard_does_not_treat_reused_stale_pid_as_running(tmp_path: Path) -> None:
    runtime = tmp_path / "state"
    exp = runtime / "experiments" / "candidate_v66_squeeze_breakout_sampler"
    (exp / "Tradeanalyse").mkdir(parents=True)
    # The current test process is alive, but it is not the strategy AutoTrader process.
    (exp / "bot.pid").write_text(str(os.getpid()), encoding="utf-8")

    snapshot = build_dashboard_snapshot(runtime_dir=runtime)

    assert snapshot.paper_bots[0].pid == os.getpid()
    assert snapshot.paper_bots[0].running is False


def test_dashboard_html_is_read_only_and_contains_key_sections(tmp_path: Path) -> None:
    runtime = tmp_path / "state"
    (runtime / "experiments" / "s1" / "Tradeanalyse").mkdir(parents=True)
    (runtime / "experiments" / "s1" / "bot.pid").write_text("999999", encoding="utf-8")

    html = render_dashboard_html(build_dashboard_snapshot(runtime_dir=runtime))

    assert "CryptoTradingBot Dashboard" in html
    assert "Read-only" in html
    assert "s1" in html
    assert "Near Miss" in html
    assert "Live-readiness Strategy Scorecard" in html
    assert "Status" in html
    assert "place order" not in html.lower()


def test_dashboard_displays_open_positions_with_unrealized_pnl(tmp_path: Path, monkeypatch) -> None:
    runtime = tmp_path / "state"
    exp = runtime / "experiments" / "candidate_v66_squeeze_breakout_sampler"
    (exp / "Tradeanalyse").mkdir(parents=True)
    (exp / "bot.pid").write_text("999999", encoding="utf-8")
    (exp / "paper_state.json").write_text(json.dumps({
        "positions": {
            "WLD": {"contracts": 100.0, "entryPrice": 0.30, "side": "long", "symbol": "WLD/USDC:USDC"}
        },
        "leverage": {"WLD/USDC:USDC": 3},
        "orders": [],
    }), encoding="utf-8")
    monkeypatch.setattr("dashboard._fetch_live_prices", lambda: {"WLD": 0.33})

    snapshot = build_dashboard_snapshot(runtime_dir=runtime)
    html = render_dashboard_html(snapshot)

    bot = snapshot.paper_bots[0]
    assert bot.open_position_count == 1
    assert bot.open_unrealized_pnl_usd == 3.0
    assert bot.scorecard.total_pnl_usd == 3.0
    assert bot.scorecard.unrealized_pnl_usd == 3.0
    assert bot.open_positions[0]["coin"] == "WLD"
    assert bot.open_positions[0]["notional_usd"] == 33.0
    assert "Open Positions" in html
    assert "WLD" in html
    assert "+3.0000" in html


def test_dashboard_marks_research_sampler_bots(tmp_path: Path) -> None:
    runtime = tmp_path / "state"
    exp = runtime / "experiments" / "candidate_v65_signal_sampler_aggressive"
    (exp / "Tradeanalyse").mkdir(parents=True)
    (exp / "bot.pid").write_text("999999", encoding="utf-8")

    html = render_dashboard_html(build_dashboard_snapshot(runtime_dir=runtime))

    assert "candidate_v65_signal_sampler_aggressive" in html
    assert "Research sampler" in html
    assert "not a champion candidate" in html
