"""Tests for curseforge.py."""

import pytest
import responses as responses_lib

from modpack_checker.curseforge import (
    CurseForgeAuthError,
    CurseForgeClient,
    CurseForgeError,
    CurseForgeNotFoundError,
    CurseForgeRateLimitError,
)

BASE = "https://api.curseforge.com"


@pytest.fixture
def client():
    return CurseForgeClient("test-api-key", timeout=5)


# ---------------------------------------------------------------------------
# get_mod
# ---------------------------------------------------------------------------


@responses_lib.activate
def test_get_mod_success(client):
    responses_lib.add(
        responses_lib.GET,
        f"{BASE}/v1/mods/123456",
        json={"data": {"id": 123456, "name": "Test Pack", "latestFiles": []}},
        status=200,
    )
    mod = client.get_mod(123456)
    assert mod["name"] == "Test Pack"


@responses_lib.activate
def test_get_mod_not_found(client):
    responses_lib.add(responses_lib.GET, f"{BASE}/v1/mods/999", status=404)
    with pytest.raises(CurseForgeNotFoundError):
        client.get_mod(999)


@responses_lib.activate
def test_get_mod_invalid_key_401(client):
    responses_lib.add(responses_lib.GET, f"{BASE}/v1/mods/123", status=401)
    with pytest.raises(CurseForgeAuthError, match="Invalid API key"):
        client.get_mod(123)


@responses_lib.activate
def test_get_mod_forbidden_403(client):
    responses_lib.add(responses_lib.GET, f"{BASE}/v1/mods/123", status=403)
    with pytest.raises(CurseForgeAuthError, match="permission"):
        client.get_mod(123)


@responses_lib.activate
def test_get_mod_rate_limit_429(client):
    responses_lib.add(responses_lib.GET, f"{BASE}/v1/mods/123", status=429)
    with pytest.raises(CurseForgeRateLimitError):
        client.get_mod(123)


@responses_lib.activate
def test_get_mod_server_error(client):
    # responses library doesn't retry by default in tests; just test the exception
    responses_lib.add(responses_lib.GET, f"{BASE}/v1/mods/123", status=500)
    responses_lib.add(responses_lib.GET, f"{BASE}/v1/mods/123", status=500)
    responses_lib.add(responses_lib.GET, f"{BASE}/v1/mods/123", status=500)
    responses_lib.add(responses_lib.GET, f"{BASE}/v1/mods/123", status=500)
    with pytest.raises(CurseForgeError):
        client.get_mod(123)


# ---------------------------------------------------------------------------
# get_mod_name
# ---------------------------------------------------------------------------


@responses_lib.activate
def test_get_mod_name(client):
    responses_lib.add(
        responses_lib.GET,
        f"{BASE}/v1/mods/100",
        json={"data": {"id": 100, "name": "All The Mods 9", "latestFiles": []}},
        status=200,
    )
    assert client.get_mod_name(100) == "All The Mods 9"


@responses_lib.activate
def test_get_mod_name_fallback(client):
    """If 'name' key is missing, return generic fallback."""
    responses_lib.add(
        responses_lib.GET,
        f"{BASE}/v1/mods/100",
        json={"data": {"id": 100, "latestFiles": []}},
        status=200,
    )
    assert client.get_mod_name(100) == "Modpack 100"


# ---------------------------------------------------------------------------
# get_latest_file
# ---------------------------------------------------------------------------


@responses_lib.activate
def test_get_latest_file_uses_latest_files(client):
    """get_latest_file should prefer the latestFiles field (fast path)."""
    responses_lib.add(
        responses_lib.GET,
        f"{BASE}/v1/mods/200",
        json={
            "data": {
                "id": 200,
                "name": "Pack",
                "latestFiles": [
                    {
                        "id": 9001,
                        "displayName": "Pack 2.0.0",
                        "fileName": "pack-2.0.0.zip",
                        "fileDate": "2026-01-15T00:00:00Z",
                    },
                    {
                        "id": 9000,
                        "displayName": "Pack 1.0.0",
                        "fileName": "pack-1.0.0.zip",
                        "fileDate": "2025-12-01T00:00:00Z",
                    },
                ],
            }
        },
        status=200,
    )
    file_obj = client.get_latest_file(200)
    assert file_obj["displayName"] == "Pack 2.0.0"


@responses_lib.activate
def test_get_latest_file_fallback_files_endpoint(client):
    """Falls back to the /files endpoint when latestFiles is empty."""
    responses_lib.add(
        responses_lib.GET,
        f"{BASE}/v1/mods/300",
        json={"data": {"id": 300, "name": "Pack", "latestFiles": []}},
        status=200,
    )
    responses_lib.add(
        responses_lib.GET,
        f"{BASE}/v1/mods/300/files",
        json={
            "data": [
                {"id": 8000, "displayName": "Pack 3.0.0", "fileName": "pack-3.0.0.zip"}
            ]
        },
        status=200,
    )
    file_obj = client.get_latest_file(300)
    assert file_obj["displayName"] == "Pack 3.0.0"


@responses_lib.activate
def test_get_latest_file_no_files_returns_none(client):
    responses_lib.add(
        responses_lib.GET,
        f"{BASE}/v1/mods/400",
        json={"data": {"id": 400, "name": "Pack", "latestFiles": []}},
        status=200,
    )
    responses_lib.add(
        responses_lib.GET,
        f"{BASE}/v1/mods/400/files",
        json={"data": []},
        status=200,
    )
    assert client.get_latest_file(400) is None


# ---------------------------------------------------------------------------
# extract_version
# ---------------------------------------------------------------------------


def test_extract_version_prefers_display_name(client):
    file_obj = {"displayName": "ATM9 1.2.3", "fileName": "atm9-1.2.3.zip", "id": 1}
    assert client.extract_version(file_obj) == "ATM9 1.2.3"


def test_extract_version_falls_back_to_filename(client):
    file_obj = {"displayName": "", "fileName": "pack-1.0.0.zip", "id": 1}
    assert client.extract_version(file_obj) == "pack-1.0.0.zip"


def test_extract_version_last_resort_file_id(client):
    file_obj = {"displayName": "", "fileName": "", "id": 9999}
    assert client.extract_version(file_obj) == "File ID 9999"


def test_extract_version_strips_whitespace(client):
    file_obj = {"displayName": "  Pack 1.0  ", "fileName": "pack.zip", "id": 1}
    assert client.extract_version(file_obj) == "Pack 1.0"


# ---------------------------------------------------------------------------
# validate_api_key
# ---------------------------------------------------------------------------


@responses_lib.activate
def test_validate_api_key_success(client):
    responses_lib.add(
        responses_lib.GET,
        f"{BASE}/v1/games/432",
        json={"data": {"id": 432, "name": "Minecraft"}},
        status=200,
    )
    assert client.validate_api_key() is True


@responses_lib.activate
def test_validate_api_key_failure(client):
    responses_lib.add(responses_lib.GET, f"{BASE}/v1/games/432", status=401)
    assert client.validate_api_key() is False
