"""Tests for the card conversion script.

These tests verify the transformation logic that converts raw scraped card data
into the CardDefinition format used by the game engine.
"""

import sys
from pathlib import Path

import pytest

# Add scripts directory to path for imports
sys.path.insert(0, str(Path(__file__).parent.parent.parent / "scripts"))

from convert_cards import (
    generate_energy_cards,
    transform_attack,
    transform_card,
    transform_pokemon_card,
    transform_trainer_card,
    transform_weakness_resistance,
    validate_card,
)


class TestTransformAttack:
    """Tests for the transform_attack function."""

    def test_basic_attack_with_damage(self):
        """Test transforming a simple attack with base damage only.

        Verifies that an attack with just damage and no modifier
        produces a damage_display of just the number.
        """
        raw_attack = {
            "name": "Tackle",
            "cost": ["colorless"],
            "damage": 20,
            "damage_modifier": None,
            "effect_text": None,
            "effect_id": None,
        }

        result = transform_attack(raw_attack)

        assert result["name"] == "Tackle"
        assert result["cost"] == ["colorless"]
        assert result["damage"] == 20
        assert result["damage_display"] == "20"
        assert "effect_description" not in result
        assert "effect_params" not in result

    def test_attack_with_plus_modifier(self):
        """Test transforming an attack with '+' damage modifier.

        Attacks like '50+' deal base damage plus additional damage
        based on some condition (e.g., coin flips).
        """
        raw_attack = {
            "name": "Double Horn",
            "cost": ["grass", "grass"],
            "damage": 50,
            "damage_modifier": "+",
            "effect_text": "Flip 2 coins. This attack does 50 damage for each heads.",
            "effect_id": None,
        }

        result = transform_attack(raw_attack)

        assert result["damage"] == 50
        assert result["damage_display"] == "50+"
        assert result["effect_params"]["damage_modifier"] == "+"
        assert "Flip 2 coins" in result["effect_description"]

    def test_attack_with_x_modifier(self):
        """Test transforming an attack with 'x' damage modifier.

        Attacks like '50x' deal damage multiplied by some factor
        (e.g., number of coin flip heads).
        """
        raw_attack = {
            "name": "Psychic",
            "cost": ["psychic", "colorless"],
            "damage": 20,
            "damage_modifier": "x",
            "effect_text": "Does 20 damage times the number of Energy attached to your opponent's Active Pokemon.",
            "effect_id": None,
        }

        result = transform_attack(raw_attack)

        assert result["damage"] == 20
        assert result["damage_display"] == "20x"
        assert result["effect_params"]["damage_modifier"] == "x"

    def test_attack_no_damage_effect_only(self):
        """Test transforming an attack that deals no damage.

        Some attacks only have effects (like status conditions)
        and don't deal direct damage.
        """
        raw_attack = {
            "name": "Confuse Ray",
            "cost": ["psychic"],
            "damage": 0,
            "damage_modifier": None,
            "effect_text": "The Defending Pokemon is now Confused.",
            "effect_id": None,
        }

        result = transform_attack(raw_attack)

        assert result["damage"] == 0
        assert "damage_display" not in result  # No display for 0 damage
        assert result["effect_description"] == "The Defending Pokemon is now Confused."

    def test_attack_with_effect_id(self):
        """Test that existing effect_id is preserved.

        Some scraped cards may already have effect IDs mapped.
        """
        raw_attack = {
            "name": "Thunder Shock",
            "cost": ["lightning"],
            "damage": 20,
            "damage_modifier": None,
            "effect_text": "Flip a coin. If heads, the Defending Pokemon is now Paralyzed.",
            "effect_id": "may_paralyze",
        }

        result = transform_attack(raw_attack)

        assert result["effect_id"] == "may_paralyze"


class TestTransformWeaknessResistance:
    """Tests for the transform_weakness_resistance function."""

    def test_transform_weakness(self):
        """Test transforming a typical weakness.

        Weaknesses have a type and a value (damage modifier).
        """
        raw_weakness = {"type": "fire", "value": 20}

        result = transform_weakness_resistance(raw_weakness)

        assert result["energy_type"] == "fire"
        assert result["value"] == 20

    def test_transform_resistance(self):
        """Test transforming a typical resistance.

        Resistances reduce damage taken from a specific type.
        """
        raw_resistance = {"type": "fighting", "value": -30}

        result = transform_weakness_resistance(raw_resistance)

        assert result["energy_type"] == "fighting"
        assert result["value"] == -30

    def test_transform_none(self):
        """Test that None input returns None.

        Not all Pokemon have weakness or resistance.
        """
        result = transform_weakness_resistance(None)
        assert result is None


class TestTransformPokemonCard:
    """Tests for transforming Pokemon cards."""

    def test_basic_pokemon(self):
        """Test transforming a basic Pokemon card.

        Verifies all fields are correctly mapped from raw to definition format.
        """
        raw_card = {
            "id": "a1-001-bulbasaur",
            "name": "Bulbasaur",
            "set_code": "a1",
            "set_name": "Genetic Apex",
            "card_number": 1,
            "rarity": "Common",
            "card_type": "pokemon",
            "image_url": "https://example.com/bulbasaur.webp",
            "image_file": "a1/001-bulbasaur.webp",
            "hp": 70,
            "pokemon_type": "grass",
            "stage": "basic",
            "evolves_from": None,
            "is_ex": False,
            "abilities": [],
            "attacks": [
                {
                    "name": "Vine Whip",
                    "cost": ["grass", "colorless"],
                    "damage": 40,
                    "damage_modifier": None,
                    "effect_text": None,
                    "effect_id": None,
                }
            ],
            "weakness": {"type": "fire", "value": 20},
            "resistance": None,
            "retreat_cost": 1,
            "flavor_text": None,
            "illustrator": "Narumi Sato",
        }

        result = transform_pokemon_card(raw_card)

        assert result["id"] == "a1-001-bulbasaur"
        assert result["name"] == "Bulbasaur"
        assert result["card_type"] == "pokemon"
        assert result["hp"] == 70
        assert result["pokemon_type"] == "grass"
        assert result["stage"] == "basic"
        assert result["variant"] == "normal"
        assert result["set_id"] == "a1"
        assert result["rarity"] == "common"
        assert result["retreat_cost"] == 1
        assert result["weakness"]["energy_type"] == "fire"
        assert len(result["attacks"]) == 1
        assert result["illustrator"] == "Narumi Sato"
        assert result["image_path"] == "a1/001-bulbasaur.webp"
        assert "mantipocket.s3" in result["image_url"]

    def test_ex_pokemon(self):
        """Test transforming an EX Pokemon card.

        EX Pokemon have is_ex=True in raw data, which maps to variant='ex'.
        """
        raw_card = {
            "id": "a1-004-venusaur-ex",
            "name": "Venusaur ex",
            "set_code": "a1",
            "card_type": "pokemon",
            "image_file": "a1/004-venusaur-ex.webp",
            "hp": 190,
            "pokemon_type": "grass",
            "stage": "stage_2",
            "evolves_from": "Ivysaur",
            "is_ex": True,
            "abilities": [],
            "attacks": [],
            "weakness": {"type": "fire", "value": 20},
            "resistance": None,
            "retreat_cost": 3,
            "rarity": "Double Rare",
            "illustrator": "PLANETA CG Works",
        }

        result = transform_pokemon_card(raw_card)

        assert result["variant"] == "ex"
        assert result["evolves_from"] == "Ivysaur"
        assert result["rarity"] == "double rare"

    def test_evolution_pokemon(self):
        """Test transforming an evolution Pokemon.

        Stage 1 and Stage 2 Pokemon must have evolves_from set.
        """
        raw_card = {
            "id": "a1-002-ivysaur",
            "name": "Ivysaur",
            "set_code": "a1",
            "card_type": "pokemon",
            "image_file": None,
            "hp": 90,
            "pokemon_type": "grass",
            "stage": "stage_1",
            "evolves_from": "Bulbasaur",
            "is_ex": False,
            "abilities": [],
            "attacks": [],
            "weakness": {"type": "fire", "value": 20},
            "resistance": None,
            "retreat_cost": 2,
            "rarity": "Uncommon",
        }

        result = transform_pokemon_card(raw_card)

        assert result["stage"] == "stage_1"
        assert result["evolves_from"] == "Bulbasaur"
        # Image path is now derived from card ID, not raw data
        assert result["image_path"] == "a1/002-ivysaur.webp"
        assert "mantipocket.s3" in result["image_url"]


class TestTransformTrainerCard:
    """Tests for transforming Trainer cards."""

    def test_supporter_card(self):
        """Test transforming a Supporter trainer card.

        Supporters are trainer cards limited to one per turn.
        """
        raw_card = {
            "id": "a1-220-misty",
            "name": "Misty",
            "set_code": "a1",
            "card_type": "trainer",
            "trainer_type": "supporter",
            "rarity": "Uncommon",
            "effect_text": "Choose 1 of your Pokemon...",
            "illustrator": "Sanosuke Sakuma",
            "image_file": "a1/220-misty.webp",
        }

        result = transform_trainer_card(raw_card)

        assert result["id"] == "a1-220-misty"
        assert result["name"] == "Misty"
        assert result["card_type"] == "trainer"
        assert result["trainer_type"] == "supporter"
        assert result["set_id"] == "a1"
        assert result["effect_description"] == "Choose 1 of your Pokemon..."
        assert result["image_path"] == "a1/220-misty.webp"


class TestTransformCard:
    """Tests for the main transform_card dispatcher."""

    def test_dispatches_to_pokemon(self):
        """Test that Pokemon cards are routed to transform_pokemon_card."""
        raw_card = {
            "id": "test-pokemon",
            "name": "Test Pokemon",
            "set_code": "test",
            "card_type": "pokemon",
            "hp": 60,
            "pokemon_type": "fire",
            "stage": "basic",
            "is_ex": False,
            "attacks": [],
            "abilities": [],
            "weakness": None,
            "resistance": None,
            "retreat_cost": 1,
            "rarity": "Common",
        }

        result = transform_card(raw_card)

        assert result["card_type"] == "pokemon"

    def test_dispatches_to_trainer(self):
        """Test that Trainer cards are routed to transform_trainer_card."""
        raw_card = {
            "id": "test-trainer",
            "name": "Test Trainer",
            "set_code": "test",
            "card_type": "trainer",
            "trainer_type": "item",
            "rarity": "Common",
        }

        result = transform_card(raw_card)

        assert result["card_type"] == "trainer"

    def test_unsupported_card_type_raises(self):
        """Test that unsupported card types raise ValueError."""
        raw_card = {
            "id": "test-unknown",
            "card_type": "unknown",
        }

        with pytest.raises(ValueError, match="Unsupported card type"):
            transform_card(raw_card)


class TestValidateCard:
    """Tests for card validation against the CardDefinition model."""

    def test_valid_pokemon_card(self):
        """Test that a valid Pokemon card passes validation."""
        card_dict = {
            "id": "test-pokemon",
            "name": "Test Pokemon",
            "card_type": "pokemon",
            "hp": 60,
            "pokemon_type": "fire",
            "stage": "basic",
            "variant": "normal",
            "set_id": "test",
            "rarity": "common",
            "retreat_cost": 1,
        }

        result = validate_card(card_dict)

        assert result.id == "test-pokemon"
        assert result.hp == 60

    def test_valid_energy_card(self):
        """Test that a valid Energy card passes validation."""
        card_dict = {
            "id": "energy-basic-fire",
            "name": "Fire Energy",
            "card_type": "energy",
            "energy_type": "fire",
            "energy_provides": ["fire"],
            "set_id": "basic",
            "rarity": "common",
        }

        result = validate_card(card_dict)

        assert result.id == "energy-basic-fire"
        assert result.energy_type.value == "fire"

    def test_invalid_pokemon_missing_hp(self):
        """Test that Pokemon without HP fails validation."""
        card_dict = {
            "id": "invalid-pokemon",
            "name": "Invalid Pokemon",
            "card_type": "pokemon",
            "hp": None,
            "pokemon_type": "fire",
            "stage": "basic",
        }

        with pytest.raises(ValueError):
            validate_card(card_dict)


class TestGenerateEnergyCards:
    """Tests for basic energy card generation."""

    def test_generates_all_energy_types(self):
        """Test that all 10 basic energy types are generated.

        The game uses 10 energy types: colorless, darkness, dragon,
        fighting, fire, grass, lightning, metal, psychic, water.
        """
        cards = generate_energy_cards()

        assert len(cards) == 10

        # Check all types are present
        energy_types = {card["energy_type"] for card in cards}
        expected_types = {
            "colorless",
            "darkness",
            "dragon",
            "fighting",
            "fire",
            "grass",
            "lightning",
            "metal",
            "psychic",
            "water",
        }
        assert energy_types == expected_types

    def test_energy_card_structure(self):
        """Test that generated energy cards have correct structure.

        Each energy card should have id, name, card_type, energy_type,
        energy_provides, rarity, set_id, and image paths.
        """
        cards = generate_energy_cards()
        grass_energy = next(c for c in cards if c["energy_type"] == "grass")

        assert grass_energy["id"] == "energy-basic-grass"
        assert grass_energy["name"] == "Grass Energy"
        assert grass_energy["card_type"] == "energy"
        assert grass_energy["energy_provides"] == ["grass"]
        assert grass_energy["rarity"] == "common"
        assert grass_energy["set_id"] == "basic"
        assert grass_energy["image_path"] == "basic/grass.webp"

    def test_energy_cards_validate(self):
        """Test that all generated energy cards pass validation.

        Each card should be valid against the CardDefinition model.
        """
        cards = generate_energy_cards()

        for card in cards:
            result = validate_card(card)
            assert result.card_type.value == "energy"
