from __future__ import annotations

import json
from pathlib import Path

from config import BotConfig
from near_miss import append_near_miss, build_near_miss_event, top_near_misses


def test_build_near_miss_event_reports_distance_to_flash_crash_trigger() -> None:
    cfg = BotConfig(flash_crash_trigger_pct=4.5, min_volume_24h=10_000_000, crash_roe_trigger_pct=15.0, default_leverage=5)
    history = [(1.0, 100.0), (2.0, 98.0), (3.0, 96.0)]

    row = build_near_miss_event(
        strategy_id="candidate",
        coin="WLD",
        history=history,
        current_price=96.0,
        reason="no_flash_crash",
        cfg=cfg,
        now_ts=123.0,
    )

    assert row is not None
    assert row.strategy_id == "candidate"
    assert row.coin == "WLD"
    assert row.drop_pct == -4.0
    assert row.required_drop_pct == 4.5
    assert row.distance_pct == 0.5
    assert row.reason == "no_flash_crash"
    assert row.roe_drop_pct == -20.0


def test_append_near_miss_journal_and_rank_closest_rows(tmp_path: Path) -> None:
    cfg = BotConfig(flash_crash_trigger_pct=4.5, min_volume_24h=1, crash_roe_trigger_pct=15.0, default_leverage=5)
    rows = [
        build_near_miss_event(strategy_id="s", coin="A", history=[(1, 100), (2, 99)], current_price=99, reason="no_flash_crash", cfg=cfg, now_ts=1),
        build_near_miss_event(strategy_id="s", coin="B", history=[(1, 100), (2, 96)], current_price=96, reason="no_flash_crash", cfg=cfg, now_ts=1),
        build_near_miss_event(strategy_id="s", coin="C", history=[(1, 100), (2, 97)], current_price=97, reason="no_flash_crash", cfg=cfg, now_ts=1),
    ]
    path = tmp_path / "near_miss.jsonl"

    for row in rows:
        assert row is not None
        append_near_miss(path, row)

    loaded = [json.loads(line) for line in path.read_text(encoding="utf-8").splitlines()]
    ranked = top_near_misses([row for row in rows if row is not None], limit=2)

    assert [row.coin for row in ranked] == ["B", "C"]
    assert loaded[0]["strategy_id"] == "s"
    assert "private" not in json.dumps(loaded).lower()
