from __future__ import annotations

import json
from pathlib import Path

from analysis.lpl_orderbook.recorder import OrderBook
from analysis.lpl_orderbook.event_replay import iter_event_frames
from analysis.lpl_orderbook.replay import replay_orderbook_window


def test_orderbook_snapshot_and_delta() -> None:
    book = OrderBook()
    book.apply_snapshot(
        {
            "bids": [{"price": "0.39", "size": "10"}],
            "asks": [{"price": "0.41", "size": "20"}],
        }
    )
    assert book.best_bid() == (0.39, 10.0)
    assert book.best_ask() == (0.41, 20.0)

    book.apply_delta(
        [
            {"side": "BUY", "price": "0.40", "size": "5"},
            {"side": "SELL", "price": "0.41", "size": "0"},
            {"side": "SELL", "price": "0.42", "size": "7"},
        ]
    )

    assert book.best_bid() == (0.4, 5.0)
    assert book.best_ask() == (0.42, 7.0)


def test_replay_orderbook_window(tmp_path: Path) -> None:
    slug = "lol-test-game1"
    market_dir = tmp_path / slug
    market_dir.mkdir(parents=True)
    (market_dir / "recording_meta.json").write_text(
        json.dumps(
            {
                "slug": slug,
                "outcomes": ["LGD", "EDG"],
                "token_ids": ["token_lgd", "token_edg"],
            }
        ),
        encoding="utf-8",
    )
    rows = [
        {
            "received_at_wall": "2026-04-23T09:00:00+00:00",
            "message_index": 1,
            "event_type": "rest_book",
            "asset_id": "token_lgd",
            "raw_json": {
                "bids": [{"price": "0.39", "size": "10"}],
                "asks": [{"price": "0.41", "size": "20"}],
            },
        },
        {
            "received_at_wall": "2026-04-23T09:00:01+00:00",
            "message_index": 2,
            "event_type": "price_change",
            "asset_id": "",
            "raw_json": {
                "price_changes": [
                    {
                        "asset_id": "token_lgd",
                        "side": "BUY",
                        "price": "0.40",
                        "size": "5",
                    }
                ]
            },
        },
    ]
    with (market_dir / "orderbook_events.jsonl").open("w", encoding="utf-8") as f:
        for row in rows:
            f.write(json.dumps(row) + "\n")

    result = replay_orderbook_window(
        slug=slug,
        at="2026-04-23T09:00:01+00:00",
        window_seconds=2,
        data_root=tmp_path,
    )

    assert result["processed_events"] == 2
    assert result["rows"] >= 2
    output = Path(str(result["output_path"])).read_text(encoding="utf-8")
    assert "token_lgd" in output
    assert "0.4" in output


def test_event_replay_reconstructs_from_events(tmp_path: Path) -> None:
    slug = "lol-test-event-game1"
    market_dir = tmp_path / slug
    market_dir.mkdir(parents=True)
    (market_dir / "recording_meta.json").write_text(
        json.dumps(
            {
                "slug": slug,
                "outcomes": ["LGD", "EDG"],
                "token_ids": ["token_lgd", "token_edg"],
            }
        ),
        encoding="utf-8",
    )
    rows = [
        {
            "received_at_wall": "2026-04-23T09:00:00.020+00:00",
            "exchange_ts": "2026-04-23T09:00:00.000+00:00",
            "message_index": 1,
            "connection_id": 1,
            "event_type": "rest_book",
            "asset_id": "token_lgd",
            "outcome": "LGD",
            "raw_json": {
                "bids": [{"price": "0.39", "size": "10"}],
                "asks": [{"price": "0.41", "size": "20"}],
            },
        },
        {
            "received_at_wall": "2026-04-23T09:00:00.030+00:00",
            "exchange_ts": "2026-04-23T09:00:00.010+00:00",
            "message_index": 2,
            "connection_id": 1,
            "event_type": "rest_book",
            "asset_id": "token_edg",
            "outcome": "EDG",
            "raw_json": {
                "bids": [{"price": "0.59", "size": "20"}],
                "asks": [{"price": "0.61", "size": "10"}],
            },
        },
        {
            "received_at_wall": "2026-04-23T09:00:01.020+00:00",
            "exchange_ts": "2026-04-23T09:00:01.000+00:00",
            "message_index": 3,
            "connection_id": 1,
            "event_type": "price_change",
            "asset_id": "",
            "outcome": "",
            "raw_json": {
                "price_changes": [
                    {
                        "asset_id": "token_lgd",
                        "side": "BUY",
                        "price": "0.40",
                        "size": "5",
                    }
                ]
            },
        },
        {
            "received_at_wall": "2026-04-23T09:00:01.040+00:00",
            "exchange_ts": "2026-04-23T09:00:01.030+00:00",
            "message_index": 4,
            "connection_id": 1,
            "event_type": "last_trade_price",
            "asset_id": "token_lgd",
            "outcome": "LGD",
            "raw_json": {
                "asset_id": "token_lgd",
                "price": "0.41",
                "size": "12",
                "side": "BUY",
                "transaction_hash": "0xabc",
            },
        },
    ]
    with (market_dir / "orderbook_events.jsonl").open("w", encoding="utf-8") as f:
        for row in rows:
            f.write(json.dumps(row) + "\n")

    _meta, frames = iter_event_frames(slug=slug, data_root=tmp_path, depth=5)

    assert [frame["event_type"] for frame in frames] == [
        "rest_book",
        "price_change",
        "last_trade_price",
    ]
    assert frames[1]["books"]["token_lgd"]["best_bid"] == 0.4
    assert frames[1]["changed_levels"][0]["price"] == 0.4
    assert frames[2]["trade"]["transaction_hash"] == "0xabc"
    assert frames[2]["delay_ms"] == 10.0
