"""Tests for aiolichess.client.AioLichess.get_statistics."""

from __future__ import annotations

from unittest.mock import AsyncMock, patch

import pytest

from aiolichess import AioLichess


# A trimmed-down sample of /api/account showing the full set of perf keys
# Lichess returns. Only the `rating` and `games` fields matter here; other
# perf metadata (rd, prog, prov) is intentionally omitted for some entries
# to exercise the optional-field handling.
SAMPLE_ACCOUNT_RESPONSE: dict = {
    "id": "drnykterstien",
    "username": "DrNykterstein",
    "url": "https://lichess.org/@/DrNykterstein",
    "createdAt": 1420502920988,
    "seenAt": 1747342929853,
    "playTime": {"total": 999999},
    "perfs": {
        "ultraBullet": {"rating": 1500, "games": 2, "rd": 50, "prog": 0},
        "bullet": {"rating": 1373, "games": 7, "rd": 50, "prog": 0},
        "blitz": {"rating": 944, "games": 31, "rd": 50, "prog": 0},
        "rapid": {"rating": 1050, "games": 324, "rd": 50, "prog": 0},
        "classical": {"rating": 888, "games": 1, "rd": 50, "prog": 0},
        "correspondence": {"rating": 1600, "games": 5, "rd": 50, "prog": 0},
        "chess960": {"rating": 1700, "games": 10, "rd": 50, "prog": 0},
        "crazyhouse": {"rating": 1800, "games": 15, "rd": 50, "prog": 0},
        "antichess": {"rating": 1900, "games": 20, "rd": 50, "prog": 0},
        "atomic": {"rating": 2000, "games": 25, "rd": 50, "prog": 0},
        "horde": {"rating": 2100, "games": 30, "rd": 50, "prog": 0},
        "kingOfTheHill": {"rating": 2200, "games": 35, "rd": 50, "prog": 0},
        "racingKings": {"rating": 2300, "games": 40, "rd": 50, "prog": 0},
        "threeCheck": {"rating": 2400, "games": 45, "rd": 50, "prog": 0},
        "puzzle": {"rating": 2500, "games": 50, "rd": 50, "prog": 0},
        # Puzzle-mode perfs that have no rating/games — must be ignored.
        "storm": {"runs": 10, "score": 42},
        "racer": {"runs": 5, "score": 21},
        "streak": {"runs": 3, "score": 11},
    },
}


@pytest.mark.asyncio
async def test_get_statistics_populates_all_perfs() -> None:
    """get_statistics returns rating + games for every supported perf."""
    client = AioLichess()
    with patch.object(
        client, "_fetch_account", AsyncMock(return_value=SAMPLE_ACCOUNT_RESPONSE)
    ):
        stats = await client.get_statistics(token="dummy")

    assert stats.ultra_bullet_rating == 1500
    assert stats.ultra_bullet_games == 2
    assert stats.bullet_rating == 1373
    assert stats.bullet_games == 7
    assert stats.blitz_rating == 944
    assert stats.blitz_games == 31
    assert stats.rapid_rating == 1050
    assert stats.rapid_games == 324
    assert stats.classical_rating == 888
    assert stats.classical_games == 1
    assert stats.correspondence_rating == 1600
    assert stats.correspondence_games == 5
    assert stats.chess960_rating == 1700
    assert stats.chess960_games == 10
    assert stats.crazyhouse_rating == 1800
    assert stats.crazyhouse_games == 15
    assert stats.antichess_rating == 1900
    assert stats.antichess_games == 20
    assert stats.atomic_rating == 2000
    assert stats.atomic_games == 25
    assert stats.horde_rating == 2100
    assert stats.horde_games == 30
    assert stats.king_of_the_hill_rating == 2200
    assert stats.king_of_the_hill_games == 35
    assert stats.racing_kings_rating == 2300
    assert stats.racing_kings_games == 40
    assert stats.three_check_rating == 2400
    assert stats.three_check_games == 45
    assert stats.puzzle_rating == 2500
    assert stats.puzzle_games == 50


@pytest.mark.asyncio
async def test_get_statistics_missing_perfs_default_to_none() -> None:
    """Perfs the user has never played are returned as None, not zero."""
    sparse_response = {
        **SAMPLE_ACCOUNT_RESPONSE,
        "perfs": {
            "bullet": {"rating": 1500, "games": 100, "rd": 50, "prog": 0},
        },
    }
    client = AioLichess()
    with patch.object(
        client, "_fetch_account", AsyncMock(return_value=sparse_response)
    ):
        stats = await client.get_statistics(token="dummy")

    assert stats.bullet_rating == 1500
    assert stats.bullet_games == 100
    assert stats.crazyhouse_rating is None
    assert stats.crazyhouse_games is None
    assert stats.ultra_bullet_rating is None
    assert stats.king_of_the_hill_rating is None
