"""
Tests for Learning Generator Service
"""
import pytest
from unittest.mock import patch, MagicMock, AsyncMock
import json

import sys
sys.path.insert(0, '/app')

from services.learning_generator import LearningGeneratorService
from models.learning_node import LearningTheme, NodeType


class TestLearningGeneratorService:
    """Tests for Learning Generator Service."""

    @pytest.fixture
    def service(self):
        """Create service instance."""
        return LearningGeneratorService()

    def test_build_generation_prompt_topographie(self, service):
        """Test prompt building for topography theme."""
        aoi_info = {
            "bounds": {"west": 9.18, "south": 47.70, "east": 9.20, "north": 47.72},
            "center": {"latitude": 47.71, "longitude": 9.19},
            "area_km2": 0.5,
        }

        prompt = service._build_generation_prompt(
            aoi_info=aoi_info,
            theme=LearningTheme.TOPOGRAPHIE,
            difficulty="mittel",
            node_count=5,
            grade_level="7-8",
            language="de",
        )

        assert "Topographie" in prompt or "topographie" in prompt
        assert "47.71" in prompt  # center latitude
        assert "9.19" in prompt  # center longitude
        assert "5" in prompt  # node count
        assert "mittel" in prompt  # difficulty
        assert "7-8" in prompt  # grade level
        assert "JSON" in prompt

    def test_build_generation_prompt_landnutzung(self, service):
        """Test prompt building for land use theme."""
        aoi_info = {
            "bounds": {"west": 9.18, "south": 47.70, "east": 9.20, "north": 47.72},
            "center": {"latitude": 47.71, "longitude": 9.19},
            "area_km2": 0.5,
        }

        prompt = service._build_generation_prompt(
            aoi_info=aoi_info,
            theme=LearningTheme.LANDNUTZUNG,
            difficulty="leicht",
            node_count=3,
            grade_level=None,
            language="de",
        )

        assert "Landnutzung" in prompt or "landnutzung" in prompt

    def test_parse_llm_response_valid(self, service):
        """Test parsing valid LLM response."""
        response = """
        Here are the learning nodes:
        [
            {
                "title": "Höhenbestimmung",
                "position": {"latitude": 47.71, "longitude": 9.19},
                "question": "Schätze die Höhe dieses Punktes.",
                "hints": ["Schau auf die Vegetation", "Vergleiche mit dem See"],
                "answer": "Ca. 500m",
                "explanation": "Die Höhe lässt sich...",
                "node_type": "question",
                "points": 10
            }
        ]
        """

        nodes = service._parse_llm_response(
            response, "test-aoi-id", LearningTheme.TOPOGRAPHIE
        )

        assert len(nodes) == 1
        assert nodes[0].title == "Höhenbestimmung"
        assert nodes[0].aoi_id == "test-aoi-id"
        assert nodes[0].theme == LearningTheme.TOPOGRAPHIE
        assert nodes[0].points == 10

    def test_parse_llm_response_invalid_json(self, service):
        """Test parsing invalid LLM response."""
        response = "This is not valid JSON"

        nodes = service._parse_llm_response(
            response, "test-aoi-id", LearningTheme.TOPOGRAPHIE
        )

        assert len(nodes) == 0

    def test_generate_mock_nodes(self, service):
        """Test mock node generation."""
        nodes = service._generate_mock_nodes(
            aoi_id="test-aoi-id",
            theme=LearningTheme.TOPOGRAPHIE,
            difficulty="mittel",
            node_count=3,
        )

        assert len(nodes) == 3
        for node in nodes:
            assert node.aoi_id == "test-aoi-id"
            assert node.theme == LearningTheme.TOPOGRAPHIE
            assert node.approved == False
            assert len(node.hints) > 0

    def test_generate_mock_nodes_orientierung(self, service):
        """Test mock node generation for orientation theme."""
        nodes = service._generate_mock_nodes(
            aoi_id="test-aoi-id",
            theme=LearningTheme.ORIENTIERUNG,
            difficulty="leicht",
            node_count=2,
        )

        assert len(nodes) == 2
        for node in nodes:
            assert node.theme == LearningTheme.ORIENTIERUNG

    @pytest.mark.asyncio
    async def test_get_nodes_for_aoi_empty(self, service):
        """Test getting nodes for non-existent AOI."""
        nodes = await service.get_nodes_for_aoi("nonexistent-aoi")
        assert nodes is None

    @pytest.mark.asyncio
    async def test_get_statistics_empty(self, service):
        """Test statistics with no data."""
        stats = await service.get_statistics()
        assert stats["total_nodes"] == 0
        assert stats["by_theme"] == {}


class TestLearningNodeModel:
    """Tests for Learning Node model."""

    def test_learning_theme_values(self):
        """Test all theme enum values exist."""
        themes = [
            LearningTheme.TOPOGRAPHIE,
            LearningTheme.LANDNUTZUNG,
            LearningTheme.ORIENTIERUNG,
            LearningTheme.GEOLOGIE,
            LearningTheme.HYDROLOGIE,
            LearningTheme.VEGETATION,
        ]
        assert len(themes) == 6

    def test_node_type_values(self):
        """Test all node type enum values exist."""
        types = [
            NodeType.QUESTION,
            NodeType.OBSERVATION,
            NodeType.EXPLORATION,
        ]
        assert len(types) == 3

    def test_create_learning_node(self):
        """Test creating a learning node."""
        from models.learning_node import LearningNode

        node = LearningNode(
            id="test-id",
            aoi_id="test-aoi",
            title="Test Station",
            theme=LearningTheme.TOPOGRAPHIE,
            position={"latitude": 47.71, "longitude": 9.19},
            question="Test question?",
            hints=["Hint 1", "Hint 2"],
            answer="Test answer",
            explanation="Test explanation",
            node_type=NodeType.QUESTION,
            points=10,
            approved=False,
        )

        assert node.id == "test-id"
        assert node.title == "Test Station"
        assert node.points == 10
        assert len(node.hints) == 2
