"""
Tests for StaticItemLoader service.

Tests the service that loads predefined items (consumables, materials)
from YAML files for use in loot tables.
"""

import pytest
from pathlib import Path

from app.services.static_item_loader import StaticItemLoader, get_static_item_loader
from app.models.enums import ItemType, ItemRarity


class TestStaticItemLoaderInitialization:
    """Test service initialization."""

    def test_init_with_default_path(self):
        """Service should initialize with default data path."""
        loader = StaticItemLoader()
        assert loader.data_dir.exists() or not loader._loaded

    def test_init_with_custom_path(self, tmp_path):
        """Service should accept custom data path."""
        loader = StaticItemLoader(data_dir=str(tmp_path))
        assert loader.data_dir == tmp_path

    def test_singleton_returns_same_instance(self):
        """get_static_item_loader should return singleton."""
        loader1 = get_static_item_loader()
        loader2 = get_static_item_loader()
        assert loader1 is loader2


class TestStaticItemLoaderLoading:
    """Test YAML loading functionality."""

    def test_loads_consumables(self):
        """Should load consumable items from YAML."""
        loader = get_static_item_loader()

        # Check that health potion exists
        assert loader.has_item("health_potion_small")
        assert loader.has_item("health_potion_medium")

    def test_loads_materials(self):
        """Should load material items from YAML."""
        loader = get_static_item_loader()

        # Check that materials exist
        assert loader.has_item("goblin_ear")
        assert loader.has_item("wolf_pelt")

    def test_get_all_item_ids_returns_list(self):
        """get_all_item_ids should return list of item IDs."""
        loader = get_static_item_loader()
        item_ids = loader.get_all_item_ids()

        assert isinstance(item_ids, list)
        assert len(item_ids) > 0
        assert "health_potion_small" in item_ids

    def test_has_item_returns_false_for_missing(self):
        """has_item should return False for non-existent items."""
        loader = get_static_item_loader()
        assert not loader.has_item("nonexistent_item_xyz")


class TestStaticItemLoaderGetItem:
    """Test item retrieval."""

    def test_get_item_returns_item_object(self):
        """get_item should return an Item instance."""
        loader = get_static_item_loader()
        item = loader.get_item("health_potion_small")

        assert item is not None
        assert item.name == "Small Health Potion"
        assert item.item_type == ItemType.CONSUMABLE
        assert item.rarity == ItemRarity.COMMON

    def test_get_item_has_unique_id(self):
        """Each call should create item with unique ID."""
        loader = get_static_item_loader()

        item1 = loader.get_item("health_potion_small")
        item2 = loader.get_item("health_potion_small")

        assert item1.item_id != item2.item_id
        assert "health_potion_small" in item1.item_id
        assert "health_potion_small" in item2.item_id

    def test_get_item_returns_none_for_missing(self):
        """get_item should return None for non-existent items."""
        loader = get_static_item_loader()
        item = loader.get_item("nonexistent_item_xyz")

        assert item is None

    def test_get_item_consumable_has_effects(self):
        """Consumable items should have effects_on_use."""
        loader = get_static_item_loader()
        item = loader.get_item("health_potion_small")

        assert len(item.effects_on_use) > 0
        effect = item.effects_on_use[0]
        assert effect.name == "Minor Healing"
        assert effect.power > 0

    def test_get_item_quest_item_type(self):
        """Quest items should have correct type."""
        loader = get_static_item_loader()
        item = loader.get_item("goblin_ear")

        assert item is not None
        assert item.item_type == ItemType.QUEST_ITEM
        assert item.rarity == ItemRarity.COMMON

    def test_get_item_has_value(self):
        """Items should have value set."""
        loader = get_static_item_loader()
        item = loader.get_item("health_potion_small")

        assert item.value > 0

    def test_get_item_is_tradeable(self):
        """Items should default to tradeable."""
        loader = get_static_item_loader()
        item = loader.get_item("goblin_ear")

        assert item.is_tradeable is True


class TestStaticItemLoaderVariousItems:
    """Test loading various item types."""

    def test_medium_health_potion(self):
        """Test medium health potion properties."""
        loader = get_static_item_loader()
        item = loader.get_item("health_potion_medium")

        assert item is not None
        assert item.rarity == ItemRarity.UNCOMMON
        assert item.value > 25  # More expensive than small

    def test_large_health_potion(self):
        """Test large health potion properties."""
        loader = get_static_item_loader()
        item = loader.get_item("health_potion_large")

        assert item is not None
        assert item.rarity == ItemRarity.RARE

    def test_chieftain_token_rarity(self):
        """Test that chieftain token is rare."""
        loader = get_static_item_loader()
        item = loader.get_item("goblin_chieftain_token")

        assert item is not None
        assert item.rarity == ItemRarity.RARE

    def test_elixir_has_buff_effect(self):
        """Test that elixirs have buff effects."""
        loader = get_static_item_loader()
        item = loader.get_item("elixir_of_strength")

        if item:  # Only test if item exists
            assert len(item.effects_on_use) > 0


class TestStaticItemLoaderCache:
    """Test caching behavior."""

    def test_clear_cache(self):
        """clear_cache should reset loaded state."""
        loader = StaticItemLoader()

        # Trigger loading
        loader._ensure_loaded()
        assert loader._loaded is True

        # Clear cache
        loader.clear_cache()
        assert loader._loaded is False
        assert len(loader._cache) == 0

    def test_lazy_loading(self):
        """Items should be loaded lazily on first access."""
        loader = StaticItemLoader()
        assert loader._loaded is False

        # Access triggers loading
        _ = loader.has_item("health_potion_small")
        assert loader._loaded is True
