"""
Tests for query paradigm system - Issue #62
"""

import pytest
import json
from markitect.query_paradigms.registry import registry
from markitect.query_paradigms.base import BaseQueryParadigm, QueryResult
from markitect.query_paradigms.paradigms.sql_paradigm import SQLQueryParadigm
from markitect.query_paradigms.paradigms.fts_paradigm import FullTextSearchParadigm
from markitect.query_paradigms.paradigms.qbe_paradigm import QueryByExampleParadigm


class TestQueryParadigmRegistry:
    """Test the query paradigm registry system."""

    def test_registry_has_paradigms(self):
        """Test that paradigms are automatically registered."""
        paradigms = registry.list_all()
        assert len(paradigms) >= 14  # We expect at least 14 paradigms

        # Check that key paradigms are present
        paradigm_names = [p.name for p in paradigms]
        assert "SQL" in paradigm_names
        assert "FTS" in paradigm_names
        assert "GraphQL" in paradigm_names
        assert "Natural Language" in paradigm_names

    def test_get_paradigm_by_name(self):
        """Test retrieving paradigms by name."""
        sql_paradigm = registry.get("SQL")
        assert sql_paradigm is not None
        assert sql_paradigm.name == "SQL"
        assert sql_paradigm.category == "structural"

        # Test case insensitive lookup
        fts_paradigm = registry.get("fts")
        assert fts_paradigm is not None
        assert fts_paradigm.name == "FTS"

    def test_get_nonexistent_paradigm(self):
        """Test getting a paradigm that doesn't exist."""
        result = registry.get("NonExistentParadigm")
        assert result is None

    def test_list_by_category(self):
        """Test filtering paradigms by category."""
        structural = registry.list_by_category("structural")
        assert len(structural) > 0

        for paradigm in structural:
            assert paradigm.category == "structural"

        textual = registry.list_by_category("textual")
        assert len(textual) > 0

        for paradigm in textual:
            assert paradigm.category == "textual"

    def test_list_by_complexity(self):
        """Test filtering paradigms by complexity."""
        beginner = registry.list_by_complexity("beginner")
        assert len(beginner) > 0

        for paradigm in beginner:
            assert paradigm.complexity == "beginner"

    def test_search_paradigms(self):
        """Test searching paradigms by query."""
        # Search by name
        sql_results = registry.search_paradigms("SQL")
        assert len(sql_results) > 0
        assert any(p.name == "SQL" for p in sql_results)

        # Search by description
        visual_results = registry.search_paradigms("visual")
        assert len(visual_results) > 0
        assert any("visual" in p.description.lower() for p in visual_results)

        # Search for non-existent term
        empty_results = registry.search_paradigms("xyznonexistent")
        assert len(empty_results) == 0

    def test_get_categories(self):
        """Test getting all available categories."""
        categories = registry.get_categories()
        assert isinstance(categories, list)
        assert len(categories) > 0
        assert "structural" in categories
        assert "textual" in categories
        assert "semantic" in categories

    def test_get_complexity_levels(self):
        """Test getting all complexity levels."""
        levels = registry.get_complexity_levels()
        assert isinstance(levels, list)
        assert len(levels) > 0
        assert "beginner" in levels
        assert "intermediate" in levels
        assert "advanced" in levels


class TestSQLParadigm:
    """Test the SQL query paradigm."""

    def test_paradigm_properties(self):
        """Test SQL paradigm basic properties."""
        paradigm = SQLQueryParadigm()
        assert paradigm.name == "SQL"
        assert paradigm.category == "structural"
        assert paradigm.complexity == "intermediate"
        assert "database" in paradigm.description.lower()

    def test_validate_query(self):
        """Test SQL query validation."""
        paradigm = SQLQueryParadigm()

        # Valid queries
        valid, error = paradigm.validate_query("SELECT * FROM files")
        assert valid
        assert error is None

        valid, error = paradigm.validate_query("SELECT name FROM files WHERE author = 'Alice'")
        assert valid

        # Invalid queries
        valid, error = paradigm.validate_query("")
        assert not valid
        assert error is not None

        valid, error = paradigm.validate_query("   ")
        assert not valid

    def test_get_examples(self):
        """Test SQL paradigm examples."""
        paradigm = SQLQueryParadigm()
        examples = paradigm.get_examples()

        assert isinstance(examples, list)
        assert len(examples) > 0

        for example in examples:
            assert "name" in example
            assert "description" in example
            assert "query" in example
            assert isinstance(example["query"], str)

    def test_get_syntax_help(self):
        """Test SQL syntax help."""
        paradigm = SQLQueryParadigm()
        help_text = paradigm.get_syntax_help()

        assert isinstance(help_text, str)
        assert len(help_text) > 0
        assert "SELECT" in help_text


class TestFTSParadigm:
    """Test the Full Text Search paradigm."""

    def test_paradigm_properties(self):
        """Test FTS paradigm basic properties."""
        paradigm = FullTextSearchParadigm()
        assert paradigm.name == "FTS"
        assert paradigm.category == "textual"
        assert paradigm.complexity == "beginner"
        assert "search" in paradigm.description.lower()

    def test_validate_query(self):
        """Test FTS query validation."""
        paradigm = FullTextSearchParadigm()

        # Valid queries
        valid, error = paradigm.validate_query("documentation")
        assert valid
        assert error is None

        valid, error = paradigm.validate_query("API AND documentation")
        assert valid

        valid, error = paradigm.validate_query('"getting started"')
        assert valid

        # Invalid queries
        valid, error = paradigm.validate_query("")
        assert not valid
        assert error is not None

    def test_get_examples(self):
        """Test FTS paradigm examples."""
        paradigm = FullTextSearchParadigm()
        examples = paradigm.get_examples()

        assert isinstance(examples, list)
        assert len(examples) > 0

        # Check for expected example types
        example_names = [ex["name"] for ex in examples]
        assert "Simple search" in example_names
        assert "Boolean search" in example_names


class TestQueryByExampleParadigm:
    """Test the Query By Example paradigm (documentation-only)."""

    def test_paradigm_properties(self):
        """Test QBE paradigm basic properties."""
        paradigm = QueryByExampleParadigm()
        assert paradigm.name == "Query By Example"
        assert paradigm.category == "visual"
        assert paradigm.complexity == "beginner"
        assert "template" in paradigm.description.lower()

    def test_validate_query(self):
        """Test QBE query validation."""
        paradigm = QueryByExampleParadigm()

        # Valid JSON templates
        valid, error = paradigm.validate_query('{"author": "Alice"}')
        assert valid
        assert error is None

        valid, error = paradigm.validate_query('{"tags": ["tutorial"], "type": "markdown"}')
        assert valid

        # Invalid queries
        valid, error = paradigm.validate_query("")
        assert not valid
        assert error is not None

        valid, error = paradigm.validate_query("not json")
        assert not valid
        assert "JSON" in error

        valid, error = paradigm.validate_query('["not", "an", "object"]')
        assert not valid
        assert "object" in error

    def test_execute_returns_not_implemented(self):
        """Test that QBE execution returns not implemented error."""
        paradigm = QueryByExampleParadigm()
        result = paradigm.execute('{"author": "Alice"}')

        assert isinstance(result, QueryResult)
        assert not result.success
        assert result.error_message is not None
        assert "not yet implemented" in result.error_message.lower()
        assert result.metadata["status"] == "not_implemented"

    def test_get_syntax_help(self):
        """Test QBE syntax help."""
        paradigm = QueryByExampleParadigm()
        help_text = paradigm.get_syntax_help()

        assert isinstance(help_text, str)
        assert len(help_text) > 0
        assert "JSON" in help_text
        assert "template" in help_text.lower()


class TestQueryResult:
    """Test the QueryResult data structure."""

    def test_query_result_creation(self):
        """Test creating a QueryResult."""
        result = QueryResult(
            paradigm="Test",
            query="test query",
            execution_time_ms=10.5,
            result_count=3,
            results=[{"id": 1}, {"id": 2}, {"id": 3}],
            metadata={"type": "test"},
            success=True
        )

        assert result.paradigm == "Test"
        assert result.query == "test query"
        assert result.execution_time_ms == 10.5
        assert result.result_count == 3
        assert len(result.results) == 3
        assert result.metadata["type"] == "test"
        assert result.success is True
        assert result.error_message is None

    def test_query_result_with_error(self):
        """Test creating a QueryResult with error."""
        result = QueryResult(
            paradigm="Test",
            query="bad query",
            execution_time_ms=1.0,
            result_count=0,
            results=[],
            metadata={},
            success=False,
            error_message="Query failed"
        )

        assert not result.success
        assert result.error_message == "Query failed"
        assert result.result_count == 0


class TestBaseQueryParadigm:
    """Test the base query paradigm interface."""

    def test_cannot_instantiate_base_class(self):
        """Test that BaseQueryParadigm cannot be instantiated directly."""
        with pytest.raises(TypeError):
            BaseQueryParadigm()

    def test_paradigm_interface(self):
        """Test that paradigms implement the required interface."""
        paradigm = SQLQueryParadigm()

        # Test all required properties
        assert hasattr(paradigm, 'name')
        assert hasattr(paradigm, 'description')
        assert hasattr(paradigm, 'category')
        assert hasattr(paradigm, 'complexity')

        # Test all required methods
        assert hasattr(paradigm, 'execute')
        assert hasattr(paradigm, 'get_examples')
        assert hasattr(paradigm, 'validate_query')
        assert hasattr(paradigm, 'get_syntax_help')

        # Test optional methods
        assert hasattr(paradigm, 'can_translate_from')
        assert hasattr(paradigm, 'translate_query')


if __name__ == "__main__":
    pytest.main([__file__])