"""Tests for AdapterRegistry — register, get, duplicates, clear."""

from typing import Any

import pytest

from wled_controller.core.game_integration.adapter_registry import AdapterRegistry
from wled_controller.core.game_integration.base_adapter import GameAdapter
from wled_controller.core.game_integration.events import GameEvent


class FakeAdapter(GameAdapter):
    ADAPTER_TYPE = "fake_game"
    DISPLAY_NAME = "Fake Game"
    GAME_NAME = "FakeGame"
    SUPPORTED_EVENTS = ["health", "kill"]

    @classmethod
    def parse_payload(
        cls,
        payload: dict[str, Any],
        adapter_config: dict[str, Any],
        prev_state: dict[str, Any],
    ) -> tuple[list[GameEvent], dict[str, Any]]:
        return [], prev_state

    @classmethod
    def validate_auth(
        cls,
        headers: dict[str, str],
        payload: dict[str, Any],
        adapter_config: dict[str, Any],
    ) -> bool:
        return True


class AnotherAdapter(GameAdapter):
    ADAPTER_TYPE = "another_game"
    DISPLAY_NAME = "Another Game"
    GAME_NAME = "AnotherGame"
    SUPPORTED_EVENTS = ["mana"]

    @classmethod
    def parse_payload(
        cls,
        payload: dict[str, Any],
        adapter_config: dict[str, Any],
        prev_state: dict[str, Any],
    ) -> tuple[list[GameEvent], dict[str, Any]]:
        return [], prev_state

    @classmethod
    def validate_auth(
        cls,
        headers: dict[str, str],
        payload: dict[str, Any],
        adapter_config: dict[str, Any],
    ) -> bool:
        return True


@pytest.fixture(autouse=True)
def _clean_registry():
    """Ensure a clean registry for each test."""
    AdapterRegistry.clear_registry()
    yield
    AdapterRegistry.clear_registry()


class TestRegister:
    def test_register_and_get(self) -> None:
        AdapterRegistry.register(FakeAdapter)
        assert AdapterRegistry.get_adapter("fake_game") is FakeAdapter

    def test_register_multiple(self) -> None:
        AdapterRegistry.register(FakeAdapter)
        AdapterRegistry.register(AnotherAdapter)
        assert AdapterRegistry.get_adapter("fake_game") is FakeAdapter
        assert AdapterRegistry.get_adapter("another_game") is AnotherAdapter

    def test_register_duplicate_overwrites(self) -> None:
        AdapterRegistry.register(FakeAdapter)
        # Re-registering the same type should overwrite without error
        AdapterRegistry.register(FakeAdapter)
        assert AdapterRegistry.get_adapter("fake_game") is FakeAdapter

    def test_register_non_subclass_raises(self) -> None:
        with pytest.raises(ValueError, match="must be a subclass"):
            AdapterRegistry.register(str)  # type: ignore[arg-type]

    def test_register_base_type_raises(self) -> None:
        with pytest.raises(ValueError, match="reserved type"):
            AdapterRegistry.register(GameAdapter)  # type: ignore[arg-type]


class TestGetAdapter:
    def test_get_unknown_raises(self) -> None:
        with pytest.raises(ValueError, match="Unknown adapter type"):
            AdapterRegistry.get_adapter("nonexistent")

    def test_get_unknown_shows_available(self) -> None:
        AdapterRegistry.register(FakeAdapter)
        with pytest.raises(ValueError, match="fake_game"):
            AdapterRegistry.get_adapter("nonexistent")


class TestGetAll:
    def test_get_all_returns_copy(self) -> None:
        AdapterRegistry.register(FakeAdapter)
        all_adapters = AdapterRegistry.get_all_adapters()
        assert "fake_game" in all_adapters

        # Mutating the copy should not affect the registry
        all_adapters.pop("fake_game")
        assert AdapterRegistry.get_adapter("fake_game") is FakeAdapter

    def test_get_available_adapters_metadata(self) -> None:
        AdapterRegistry.register(FakeAdapter)
        available = AdapterRegistry.get_available_adapters()

        assert len(available) == 1
        meta = available[0]
        assert meta["adapter_type"] == "fake_game"
        assert meta["display_name"] == "Fake Game"
        assert meta["game_name"] == "FakeGame"
        assert meta["supported_events"] == ["health", "kill"]


class TestClear:
    def test_clear_removes_all(self) -> None:
        AdapterRegistry.register(FakeAdapter)
        AdapterRegistry.register(AnotherAdapter)
        AdapterRegistry.clear_registry()

        assert AdapterRegistry.get_all_adapters() == {}
