from __future__ import annotations

import json
from collections import Counter

import pytest
from coolrl_lost_cities.games.classic.game import GameState, classic_config

from coolrl_lost_cities.games.classic.match_record import (
    FORMAT_ID,
    MatchRecord,
    decode_public_hands,
    encode_public_hands,
    make_step,
)


def _record() -> MatchRecord:
    state = GameState.new_game(classic_config(), seed=17)
    public = [Counter(), Counter()]
    steps = [
        make_step(
            index=0,
            state=state,
            public_hands=public,
            actor=None,
            phase_before=None,
            action_id=None,
        )
    ]
    before_player, before_phase = state.current_player, state.phase
    action = state.unified_legal_actions()[0]
    state.apply_unified_action(action)
    steps.append(
        make_step(
            index=1,
            state=state,
            public_hands=public,
            actor=before_player,
            phase_before=before_phase,
            action_id=action,
        )
    )
    return MatchRecord(
        metadata={"type": "metadata", "format": FORMAT_ID, "complete": False},
        steps=steps,
    )


def test_match_record_jsonl_round_trip(tmp_path) -> None:
    record = _record()
    path = record.write_jsonl(tmp_path / "match.jsonl")

    restored = MatchRecord.read_jsonl(path)

    assert restored.metadata == record.metadata
    assert restored.steps == record.steps
    assert len(path.read_text().splitlines()) == 3


def test_public_hand_encoding_is_stable_and_counted() -> None:
    counts = [Counter({(2, 7): 1, (0, 0): 2}), Counter()]
    encoded = encode_public_hands(counts)

    assert encoded[0] == [
        {"color": 0, "value": 0, "count": 2},
        {"color": 2, "value": 7, "count": 1},
    ]
    assert decode_public_hands(encoded) == counts


def test_match_record_rejects_unknown_format(tmp_path) -> None:
    path = tmp_path / "future.jsonl"
    rows = [
        {"type": "metadata", "format": "coolrl.lost-cities.match.v2"},
        _record().steps[0],
    ]
    path.write_text("\n".join(json.dumps(row) for row in rows) + "\n")

    with pytest.raises(ValueError, match="unsupported match format"):
        MatchRecord.read_jsonl(path)


def test_match_record_rejects_noncontiguous_steps() -> None:
    record = _record()
    record.steps[1]["index"] = 3

    with pytest.raises(ValueError, match="contiguous"):
        record.validate()


def test_match_record_rejects_state_not_produced_by_action() -> None:
    record = _record()
    record.steps[1]["action_id"] = record.steps[1]["action_id"] + 1

    with pytest.raises(ValueError, match="state does not follow|invalid action"):
        record.validate()
