"""
Tests for SearchAgent (WO-ECHO-SEARCH-AGENT-REAL-01)

Tests:
1. Agent availability - ripgrep check
2. Search term extraction - query parsing
3. Empty results handling - no docs scenario
4. Local docs search - using fixture docs
5. Source citation format - docs/file:line
"""

import pytest
from pathlib import Path

# Configure pytest-anyio for async tests
pytest_plugins = ('anyio',)


@pytest.fixture
def anyio_backend():
    return 'asyncio'


# Test fixtures directory
FIXTURES_DIR = Path(__file__).parent / "fixtures" / "docs"


# =============================================================================
# Test Agent Availability
# =============================================================================

class TestSearchAgentAvailability:
    """Tests for SearchAgent availability checking."""

    def test_agent_type(self):
        """Test agent type property."""
        from helix_cdc.echo.agents.search_agent import SearchAgent

        agent = SearchAgent()
        assert agent.agent_type == "search"

    def test_available_checks_ripgrep(self):
        """Test that available() checks for ripgrep."""
        from helix_cdc.echo.agents.search_agent import SearchAgent

        agent = SearchAgent()
        available = agent.available()

        # Should return bool (True if ripgrep installed)
        assert isinstance(available, bool)

    def test_has_docs_with_empty_dir(self, tmp_path):
        """Test _has_docs returns False for empty directory."""
        from helix_cdc.echo.agents.search_agent import SearchAgent

        agent = SearchAgent(docs_path=tmp_path)
        assert agent._has_docs() is False

    def test_has_docs_with_md_files(self, tmp_path):
        """Test _has_docs returns True when md files exist."""
        from helix_cdc.echo.agents.search_agent import SearchAgent

        # Create a test md file
        (tmp_path / "test.md").write_text("# Test")

        agent = SearchAgent(docs_path=tmp_path)
        assert agent._has_docs() is True


# =============================================================================
# Test Search Term Extraction
# =============================================================================

class TestSearchTermExtraction:
    """Tests for _extract_search_terms()."""

    def test_extract_quoted_strings(self):
        """Test extraction of quoted exact matches."""
        from helix_cdc.echo.agents.search_agent import SearchAgent

        agent = SearchAgent()
        terms = agent._extract_search_terms('Search for "path parameters"')

        assert "path parameters" in terms

    def test_extract_dotted_patterns(self):
        """Test extraction of module.function patterns."""
        from helix_cdc.echo.agents.search_agent import SearchAgent

        agent = SearchAgent()
        terms = agent._extract_search_terms("What is asyncio.gather?")

        assert "asyncio.gather" in terms

    def test_extract_camelcase(self):
        """Test extraction of CamelCase identifiers."""
        from helix_cdc.echo.agents.search_agent import SearchAgent

        agent = SearchAgent()
        terms = agent._extract_search_terms("How do I use FastAPI?")

        assert "FastAPI" in terms

    def test_extract_snake_case(self):
        """Test extraction of snake_case identifiers."""
        from helix_cdc.echo.agents.search_agent import SearchAgent

        agent = SearchAgent()
        terms = agent._extract_search_terms("Where is path_params defined?")

        assert "path_params" in terms

    def test_filters_stop_words(self):
        """Test that common stop words are filtered."""
        from helix_cdc.echo.agents.search_agent import SearchAgent

        agent = SearchAgent()
        terms = agent._extract_search_terms("How do I use this documentation?")

        # Stop words should not appear
        stop_words = {"how", "do", "use", "this", "documentation"}
        for term in terms:
            assert term.lower() not in stop_words

    def test_fallback_to_python(self):
        """Test fallback when no terms extracted."""
        from helix_cdc.echo.agents.search_agent import SearchAgent

        agent = SearchAgent()
        terms = agent._extract_search_terms("How do I do this?")

        # Should have fallback
        assert len(terms) > 0


# =============================================================================
# Test Empty Results Handling
# =============================================================================

class TestEmptyResultsHandling:
    """Tests for handling when no docs are available."""

    @pytest.mark.anyio
    async def test_no_docs_returns_helpful_error(self, tmp_path):
        """Test that missing docs returns helpful error message."""
        from helix_cdc.echo.agents.search_agent import SearchAgent

        agent = SearchAgent(docs_path=tmp_path)

        if not agent.available():
            pytest.skip("ripgrep not available")

        result = await agent.execute("How do I use FastAPI?", {})

        assert result.agent_type == "search"
        assert result.error is not None
        assert "build_docs_index.py" in result.error or "No documentation" in result.error
        assert result.confidence == 0.0

    @pytest.mark.anyio
    async def test_no_matches_returns_error(self):
        """Test that no matches returns appropriate error."""
        from helix_cdc.echo.agents.search_agent import SearchAgent

        agent = SearchAgent(docs_path=FIXTURES_DIR)

        if not agent.available():
            pytest.skip("ripgrep not available")

        # Search for something not in fixtures
        result = await agent.execute("What is quantum computing?", {})

        # Should have error about no matches
        if result.result and result.result.get("match_count", 0) == 0:
            assert result.error is not None


# =============================================================================
# Test Local Docs Search
# =============================================================================

class TestLocalDocsSearch:
    """Tests for searching local documentation fixtures."""

    @pytest.mark.anyio
    async def test_search_finds_fastapi_content(self):
        """Test searching for FastAPI content in fixtures."""
        from helix_cdc.echo.agents.search_agent import SearchAgent

        agent = SearchAgent(docs_path=FIXTURES_DIR)

        if not agent.available():
            pytest.skip("ripgrep not available")

        result = await agent.execute("How do I use path parameters?", {})

        assert result.agent_type == "search"

        if result.result and result.result.get("match_count", 0) > 0:
            assert result.confidence > 0.0
            assert len(result.sources) > 0

    @pytest.mark.anyio
    async def test_search_finds_asyncio_content(self):
        """Test searching for asyncio content in fixtures."""
        from helix_cdc.echo.agents.search_agent import SearchAgent

        agent = SearchAgent(docs_path=FIXTURES_DIR)

        if not agent.available():
            pytest.skip("ripgrep not available")

        result = await agent.execute("What is asyncio.gather?", {})

        assert result.agent_type == "search"

        if result.result and result.result.get("match_count", 0) > 0:
            # Should find asyncio content
            matches = result.result.get("matches", [])
            assert any("asyncio" in m.get("content", "").lower() for m in matches)

    @pytest.mark.anyio
    async def test_result_includes_search_terms(self):
        """Test that result includes extracted search terms."""
        from helix_cdc.echo.agents.search_agent import SearchAgent

        agent = SearchAgent(docs_path=FIXTURES_DIR)

        if not agent.available():
            pytest.skip("ripgrep not available")

        result = await agent.execute("FastAPI path parameters", {})

        if result.result:
            assert "search_terms" in result.result
            assert isinstance(result.result["search_terms"], list)
            assert len(result.result["search_terms"]) > 0


# =============================================================================
# Test Source Citation Format
# =============================================================================

class TestSourceCitationFormat:
    """Tests for source citation format."""

    @pytest.mark.anyio
    async def test_sources_have_docs_prefix(self):
        """Test that sources have docs/ prefix."""
        from helix_cdc.echo.agents.search_agent import SearchAgent

        agent = SearchAgent(docs_path=FIXTURES_DIR)

        if not agent.available():
            pytest.skip("ripgrep not available")

        result = await agent.execute("path parameters", {})

        if result.sources:
            for source in result.sources:
                assert source.startswith("docs/"), f"Source should start with docs/: {source}"

    @pytest.mark.anyio
    async def test_sources_have_line_numbers(self):
        """Test that sources include line numbers."""
        from helix_cdc.echo.agents.search_agent import SearchAgent

        agent = SearchAgent(docs_path=FIXTURES_DIR)

        if not agent.available():
            pytest.skip("ripgrep not available")

        result = await agent.execute("FastAPI", {})

        if result.sources:
            for source in result.sources:
                # Should be format: docs/file.md:line
                assert ":" in source, f"Source should have line number: {source}"
                parts = source.rsplit(":", 1)
                assert len(parts) == 2
                assert parts[1].isdigit(), f"Line number should be numeric: {source}"

    @pytest.mark.anyio
    async def test_matches_include_content_snippets(self):
        """Test that matches include content snippets."""
        from helix_cdc.echo.agents.search_agent import SearchAgent

        agent = SearchAgent(docs_path=FIXTURES_DIR)

        if not agent.available():
            pytest.skip("ripgrep not available")

        result = await agent.execute("path parameters", {})

        if result.result and result.result.get("matches"):
            for match in result.result["matches"]:
                assert "content" in match
                assert "file" in match
                assert "line" in match


# =============================================================================
# Test AgentResult Structure
# =============================================================================

class TestAgentResultStructure:
    """Tests for AgentResult data structure."""

    @pytest.mark.anyio
    async def test_result_has_required_fields(self):
        """Test that AgentResult has all required fields."""
        from helix_cdc.echo.agents.search_agent import SearchAgent
        from helix_cdc.echo.agents import AgentResult

        agent = SearchAgent(docs_path=FIXTURES_DIR)

        if not agent.available():
            pytest.skip("ripgrep not available")

        result = await agent.execute("test query", {})

        assert isinstance(result, AgentResult)
        assert result.agent_id is not None
        assert result.agent_type == "search"
        assert result.query == "test query"
        assert isinstance(result.sources, list)
        assert isinstance(result.confidence, float)
        assert isinstance(result.elapsed_ms, float)
        assert result.elapsed_ms >= 0

    @pytest.mark.anyio
    async def test_result_serializes_to_dict(self):
        """Test that AgentResult can be serialized."""
        from helix_cdc.echo.agents.search_agent import SearchAgent

        agent = SearchAgent(docs_path=FIXTURES_DIR)

        if not agent.available():
            pytest.skip("ripgrep not available")

        result = await agent.execute("asyncio", {})
        result_dict = result.to_dict()

        assert isinstance(result_dict, dict)
        assert "agent_id" in result_dict
        assert "agent_type" in result_dict
        assert "query" in result_dict
        assert "confidence" in result_dict


# =============================================================================
# Test Integration with Agent Registry
# =============================================================================

class TestAgentRegistryIntegration:
    """Tests for SearchAgent registration."""

    def test_search_agent_registered(self):
        """Test that SearchAgent is auto-registered."""
        from helix_cdc.echo.agents import search_agent  # noqa: F401
        from helix_cdc.echo.agents import AGENT_REGISTRY

        assert "search" in AGENT_REGISTRY

    def test_get_agents_for_temporal(self):
        """Test that search agent is returned for temporal uncertainty."""
        from helix_cdc.echo.agents import get_agents_for_uncertainty
        from helix_cdc.echo.agents import search_agent  # noqa: F401

        agents = get_agents_for_uncertainty("temporal")
        assert "search" in agents


# =============================================================================
# Run tests
# =============================================================================

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