"""
Unit tests for prompt templates module.
"""

import pytest
from pathlib import Path

from app.ai import (
    PromptTemplates,
    PromptTemplateError,
    get_prompt_templates,
    render_prompt,
)


class TestPromptTemplates:
    """Tests for PromptTemplates class."""

    def setup_method(self):
        """Set up test fixtures."""
        self.templates = PromptTemplates()

    def test_initialization(self):
        """Test PromptTemplates initializes correctly."""
        assert self.templates is not None
        assert self.templates.env is not None

    def test_template_directory_exists(self):
        """Test that template directory is created."""
        assert self.templates.template_dir.exists()

    def test_get_template_names(self):
        """Test listing available templates."""
        names = self.templates.get_template_names()
        assert isinstance(names, list)
        # Should have our 4 core templates
        assert 'story_action.j2' in names
        assert 'combat_action.j2' in names
        assert 'quest_offering.j2' in names
        assert 'npc_dialogue.j2' in names

    def test_render_string_simple(self):
        """Test rendering a simple template string."""
        result = self.templates.render_string(
            "Hello, {{ name }}!",
            name="Player"
        )
        assert result == "Hello, Player!"

    def test_render_string_with_filter(self):
        """Test rendering with custom filter."""
        result = self.templates.render_string(
            "{{ items | format_inventory }}",
            items=[
                {"name": "Sword", "quantity": 1},
                {"name": "Potion", "quantity": 3}
            ]
        )
        assert "Sword" in result
        assert "Potion (x3)" in result

    def test_render_story_action_template(self):
        """Test rendering story_action template."""
        result = self.templates.render(
            "story_action.j2",
            character={
                "name": "Aldric",
                "level": 5,
                "player_class": "Warrior",
                "current_hp": 45,
                "max_hp": 50,
                "stats": {"strength": 16, "dexterity": 12},
                "skills": [],
                "effects": []
            },
            game_state={
                "current_location": "The Rusty Anchor",
                "location_type": "TAVERN",
                "active_quests": [],
                "discovered_locations": []
            },
            action="I look around the tavern for anyone suspicious"
        )

        assert "Aldric" in result
        assert "Warrior" in result
        assert "Rusty Anchor" in result
        assert "suspicious" in result

    def test_render_combat_action_template(self):
        """Test rendering combat_action template."""
        result = self.templates.render(
            "combat_action.j2",
            character={
                "name": "Aldric",
                "level": 5,
                "player_class": "Warrior",
                "current_hp": 45,
                "max_hp": 50,
                "effects": []
            },
            combat_state={
                "round_number": 2,
                "current_turn": "Player",
                "enemies": [
                    {
                        "name": "Goblin",
                        "current_hp": 8,
                        "max_hp": 15,
                        "effects": []
                    }
                ]
            },
            action="swings their sword at the Goblin",
            action_result={
                "hit": True,
                "damage": 7,
                "effects_applied": []
            },
            is_critical=False,
            is_finishing_blow=False
        )

        assert "Aldric" in result
        assert "Goblin" in result
        assert "sword" in result

    def test_render_quest_offering_template(self):
        """Test rendering quest_offering template."""
        result = self.templates.render(
            "quest_offering.j2",
            character={
                "name": "Aldric",
                "level": 3,
                "player_class": "Warrior",
                "completed_quests": []
            },
            game_context={
                "current_location": "Village Square",
                "location_type": "TOWN",
                "active_quests": [],
                "world_events": []
            },
            eligible_quests=[
                {
                    "quest_id": "quest_goblin_cave",
                    "name": "Clear the Goblin Cave",
                    "difficulty": "EASY",
                    "quest_giver": "Village Elder",
                    "description": "Goblins have been raiding farms",
                    "narrative_hooks": [
                        "Farmers complaining about lost livestock"
                    ]
                }
            ],
            recent_actions=["Talked to locals"]
        )

        assert "quest_goblin_cave" in result
        assert "Clear the Goblin Cave" in result
        assert "Village Elder" in result

    def test_render_npc_dialogue_template(self):
        """Test rendering npc_dialogue template."""
        result = self.templates.render(
            "npc_dialogue.j2",
            character={
                "name": "Aldric",
                "level": 5,
                "player_class": "Warrior"
            },
            npc={
                "name": "Grizzled Bartender",
                "role": "Tavern Owner",
                "personality": "Gruff but kind",
                "speaking_style": "Short sentences, common slang"
            },
            conversation_topic="What's the latest news around here?",
            game_state={
                "current_location": "The Rusty Anchor",
                "time_of_day": "Evening",
                "active_quests": []
            }
        )

        assert "Grizzled Bartender" in result
        assert "Aldric" in result
        assert "news" in result

    def test_format_inventory_filter_empty(self):
        """Test format_inventory filter with empty list."""
        result = PromptTemplates._format_inventory([])
        assert result == "Empty inventory"

    def test_format_inventory_filter_single(self):
        """Test format_inventory filter with single item."""
        result = PromptTemplates._format_inventory([
            {"name": "Sword", "quantity": 1}
        ])
        assert result == "Sword"

    def test_format_inventory_filter_multiple(self):
        """Test format_inventory filter with multiple items."""
        result = PromptTemplates._format_inventory([
            {"name": "Sword", "quantity": 1},
            {"name": "Shield", "quantity": 1},
            {"name": "Potion", "quantity": 5}
        ])
        assert "Sword" in result
        assert "Shield" in result
        assert "Potion (x5)" in result

    def test_format_inventory_filter_truncation(self):
        """Test format_inventory filter truncates long lists."""
        items = [{"name": f"Item{i}", "quantity": 1} for i in range(15)]
        result = PromptTemplates._format_inventory(items, max_items=10)
        assert "and 5 more items" in result

    def test_format_stats_filter(self):
        """Test format_stats filter."""
        result = PromptTemplates._format_stats({
            "strength": 16,
            "dexterity": 14
        })
        assert "Strength: 16" in result
        assert "Dexterity: 14" in result

    def test_format_stats_filter_empty(self):
        """Test format_stats filter with empty dict."""
        result = PromptTemplates._format_stats({})
        assert result == "No stats available"

    def test_format_skills_filter(self):
        """Test format_skills filter."""
        result = PromptTemplates._format_skills([
            {"name": "Sword Mastery", "level": 3},
            {"name": "Shield Block", "level": 2}
        ])
        assert "Sword Mastery (Lv.3)" in result
        assert "Shield Block (Lv.2)" in result

    def test_format_skills_filter_empty(self):
        """Test format_skills filter with empty list."""
        result = PromptTemplates._format_skills([])
        assert result == "No skills"

    def test_format_effects_filter(self):
        """Test format_effects filter."""
        result = PromptTemplates._format_effects([
            {"name": "Blessed", "remaining_turns": 3},
            {"name": "Strength Buff"}
        ])
        assert "Blessed (3 turns)" in result
        assert "Strength Buff" in result

    def test_format_effects_filter_empty(self):
        """Test format_effects filter with empty list."""
        result = PromptTemplates._format_effects([])
        assert result == "No active effects"

    def test_truncate_text_filter_short(self):
        """Test truncate_text filter with short text."""
        result = PromptTemplates._truncate_text("Hello", 100)
        assert result == "Hello"

    def test_truncate_text_filter_long(self):
        """Test truncate_text filter with long text."""
        long_text = "A" * 150
        result = PromptTemplates._truncate_text(long_text, 100)
        assert len(result) == 100
        assert result.endswith("...")

    def test_format_gold_filter(self):
        """Test format_gold filter."""
        assert PromptTemplates._format_gold(1000) == "1,000 gold"
        assert PromptTemplates._format_gold(1000000) == "1,000,000 gold"
        assert PromptTemplates._format_gold(50) == "50 gold"

    def test_invalid_template_raises_error(self):
        """Test that invalid template raises PromptTemplateError."""
        with pytest.raises(PromptTemplateError):
            self.templates.render("nonexistent_template.j2")

    def test_invalid_template_string_raises_error(self):
        """Test that invalid template string raises PromptTemplateError."""
        with pytest.raises(PromptTemplateError):
            self.templates.render_string("{{ invalid syntax")


class TestPromptTemplateConvenienceFunctions:
    """Tests for module-level convenience functions."""

    def test_get_prompt_templates_singleton(self):
        """Test get_prompt_templates returns singleton."""
        templates1 = get_prompt_templates()
        templates2 = get_prompt_templates()
        assert templates1 is templates2

    def test_render_prompt_function(self):
        """Test render_prompt convenience function."""
        result = render_prompt(
            "story_action.j2",
            character={
                "name": "Test",
                "level": 1,
                "player_class": "Warrior",
                "current_hp": 10,
                "max_hp": 10,
                "stats": {},
                "skills": [],
                "effects": []
            },
            game_state={
                "current_location": "Test Location",
                "location_type": "TOWN",
                "active_quests": []
            },
            action="test action"
        )
        assert "Test" in result
        assert "test action" in result
