"""Tests for community adapter YAML loader."""

import textwrap
from pathlib import Path

import pytest

from wled_controller.core.game_integration.community_loader import (
    clear_community_adapters,
    get_community_adapter,
    get_community_adapter_info,
    get_community_adapters,
    load_community_adapters,
    register_community_adapters,
)


@pytest.fixture(autouse=True)
def _clean_registry() -> None:
    """Clear community adapters before and after each test."""
    clear_community_adapters()
    yield  # type: ignore[misc]
    clear_community_adapters()


def _write_yaml(directory: Path, name: str, content: str) -> Path:
    """Write a YAML file to a directory."""
    path = directory / name
    path.write_text(textwrap.dedent(content))
    return path


class TestLoadCommunityAdapters:
    def test_load_from_directory(self, tmp_path: Path) -> None:
        _write_yaml(
            tmp_path,
            "test_game.yaml",
            """\
            name: test_game
            game: Test Game
            protocol: webhook
            mappings:
              - source_path: player.health
                event: health
                min: 0
                max: 100
        """,
        )

        adapters = load_community_adapters(tmp_path)
        assert "community_test_game" in adapters
        assert adapters["community_test_game"].game == "Test Game"

    def test_load_multiple_files(self, tmp_path: Path) -> None:
        _write_yaml(
            tmp_path,
            "game_a.yaml",
            """\
            name: game_a
            game: Game A
            protocol: webhook
            mappings:
              - source_path: hp
                event: health
        """,
        )
        _write_yaml(
            tmp_path,
            "game_b.yaml",
            """\
            name: game_b
            game: Game B
            protocol: webhook
            mappings:
              - source_path: mp
                event: mana
        """,
        )

        adapters = load_community_adapters(tmp_path)
        assert len(adapters) == 2
        assert "community_game_a" in adapters
        assert "community_game_b" in adapters

    def test_load_nonexistent_directory(self, tmp_path: Path) -> None:
        nonexistent = tmp_path / "does_not_exist"
        adapters = load_community_adapters(nonexistent)
        assert adapters == {}

    def test_skip_invalid_yaml(self, tmp_path: Path) -> None:
        _write_yaml(
            tmp_path,
            "valid.yaml",
            """\
            name: valid
            game: Valid Game
            protocol: webhook
            mappings:
              - source_path: hp
                event: health
        """,
        )
        _write_yaml(
            tmp_path,
            "invalid.yaml",
            """\
            name: invalid
            protocol: webhook
            mappings: []
        """,
        )

        adapters = load_community_adapters(tmp_path)
        assert len(adapters) == 1
        assert "community_valid" in adapters

    def test_load_yml_extension(self, tmp_path: Path) -> None:
        _write_yaml(
            tmp_path,
            "game.yml",
            """\
            name: yml_game
            game: YML Game
            protocol: webhook
            mappings:
              - source_path: hp
                event: health
        """,
        )

        adapters = load_community_adapters(tmp_path)
        assert "community_game" in adapters

    def test_empty_directory(self, tmp_path: Path) -> None:
        adapters = load_community_adapters(tmp_path)
        assert adapters == {}


class TestRegisterCommunityAdapters:
    def test_register_and_retrieve(self, tmp_path: Path) -> None:
        _write_yaml(
            tmp_path,
            "test.yaml",
            """\
            name: test
            game: Test
            protocol: webhook
            mappings:
              - source_path: hp
                event: health
        """,
        )

        count = register_community_adapters(tmp_path)
        assert count == 1

        adapters = get_community_adapters()
        assert "community_test" in adapters

    def test_get_single_adapter(self, tmp_path: Path) -> None:
        _write_yaml(
            tmp_path,
            "test.yaml",
            """\
            name: test
            game: Test
            protocol: webhook
            mappings:
              - source_path: hp
                event: health
        """,
        )

        register_community_adapters(tmp_path)
        adapter = get_community_adapter("community_test")
        assert adapter is not None
        assert adapter.name == "test"

    def test_get_nonexistent_adapter(self) -> None:
        adapter = get_community_adapter("community_nonexistent")
        assert adapter is None

    def test_get_adapter_info(self, tmp_path: Path) -> None:
        _write_yaml(
            tmp_path,
            "my_game.yaml",
            """\
            name: My Game Adapter
            game: My Game
            protocol: webhook
            mappings:
              - source_path: hp
                event: health
              - source_path: kills
                event: kill
        """,
        )

        register_community_adapters(tmp_path)
        info = get_community_adapter_info()
        assert len(info) == 1
        assert info[0]["adapter_type"] == "community_my_game"
        assert info[0]["display_name"] == "My Game Adapter"
        assert info[0]["game_name"] == "My Game"
        assert info[0]["source"] == "community"
        assert "health" in info[0]["supported_events"]
        assert "kill" in info[0]["supported_events"]


class TestBuiltInYamlFiles:
    """Test that the shipped YAML adapter files load correctly."""

    def test_load_bundled_adapters(self) -> None:
        """Load the built-in game_adapters directory."""
        bundled_dir = (
            Path(__file__).parent.parent.parent
            / "src"
            / "wled_controller"
            / "data"
            / "game_adapters"
        )
        if not bundled_dir.exists():
            pytest.skip("Bundled adapter directory not found")

        adapters = load_community_adapters(bundled_dir)
        # We ship minecraft, valorant, rocket_league
        assert len(adapters) >= 3
        assert "community_minecraft" in adapters
        assert "community_valorant" in adapters
        assert "community_rocket_league" in adapters

    def test_minecraft_adapter_parses(self) -> None:
        """Test that the Minecraft community adapter can parse a payload."""
        bundled_dir = (
            Path(__file__).parent.parent.parent
            / "src"
            / "wled_controller"
            / "data"
            / "game_adapters"
        )
        adapters = load_community_adapters(bundled_dir)
        mc = adapters.get("community_minecraft")
        if mc is None:
            pytest.skip("Minecraft adapter not found")

        payload = {
            "player": {
                "health": 15,
                "armor": 10,
                "food_level": 18,
                "experience_level": 30,
            },
            "stats": {"kills": 5},
        }
        events, _ = mc.parse_payload(payload, {"adapter_id": "mc_test"}, {})
        types = {e.event_type for e in events}
        assert "health" in types
        assert "armor" in types

    def test_rocket_league_adapter_parses(self) -> None:
        """Test that the Rocket League community adapter can parse a payload."""
        bundled_dir = (
            Path(__file__).parent.parent.parent
            / "src"
            / "wled_controller"
            / "data"
            / "game_adapters"
        )
        adapters = load_community_adapters(bundled_dir)
        rl = adapters.get("community_rocket_league")
        if rl is None:
            pytest.skip("Rocket League adapter not found")

        payload = {
            "player": {"boost": 50, "speed": 1150},
            "match": {"goals_scored": 2, "goals_conceded": 1, "time_remaining": 150},
            "team": {"score_blue": 2, "score_orange": 1},
        }
        events, _ = rl.parse_payload(payload, {"adapter_id": "rl_test"}, {})
        types = {e.event_type for e in events}
        assert "energy" in types
        assert "speed" in types
