"""
Tests for advanced_search_system/knowledge/standard_knowledge.py

Tests cover:
- StandardKnowledge initialization
- generate_knowledge method
- generate_sub_knowledge method
- generate method
- compress_knowledge method
- format_citations method
"""

from unittest.mock import Mock


class TestStandardKnowledgeInit:
    """Tests for StandardKnowledge initialization."""

    def test_inherits_from_base_knowledge(self):
        """Test that StandardKnowledge inherits from BaseKnowledgeGenerator."""
        from local_deep_research.advanced_search_system.knowledge.standard_knowledge import (
            StandardKnowledge,
        )
        from local_deep_research.advanced_search_system.knowledge.base_knowledge import (
            BaseKnowledgeGenerator,
        )

        assert issubclass(StandardKnowledge, BaseKnowledgeGenerator)

    def test_stores_model(self):
        """Test that model is stored."""
        from local_deep_research.advanced_search_system.knowledge.standard_knowledge import (
            StandardKnowledge,
        )

        mock_model = Mock()
        knowledge = StandardKnowledge(mock_model)

        assert knowledge.model is mock_model


class TestGenerateKnowledge:
    """Tests for generate_knowledge method."""

    def test_generates_knowledge_from_query(self):
        """Test generating knowledge from query."""
        from local_deep_research.advanced_search_system.knowledge.standard_knowledge import (
            StandardKnowledge,
        )

        mock_model = Mock()
        mock_model.invoke.return_value = Mock(
            content="Generated knowledge about topic"
        )

        knowledge = StandardKnowledge(mock_model)
        result = knowledge.generate_knowledge("What is quantum computing?")

        assert result == "Generated knowledge about topic"
        mock_model.invoke.assert_called_once()

    def test_includes_query_in_prompt(self):
        """Test that query is included in prompt."""
        from local_deep_research.advanced_search_system.knowledge.standard_knowledge import (
            StandardKnowledge,
        )

        mock_model = Mock()
        mock_model.invoke.return_value = Mock(content="Knowledge")

        knowledge = StandardKnowledge(mock_model)
        knowledge.generate_knowledge("Quantum computing applications")

        call_args = mock_model.invoke.call_args[0][0]
        assert "Quantum computing applications" in call_args

    def test_includes_context_in_prompt(self):
        """Test that context is included in prompt."""
        from local_deep_research.advanced_search_system.knowledge.standard_knowledge import (
            StandardKnowledge,
        )

        mock_model = Mock()
        mock_model.invoke.return_value = Mock(content="Knowledge")

        knowledge = StandardKnowledge(mock_model)
        knowledge.generate_knowledge("Query", context="Additional context info")

        call_args = mock_model.invoke.call_args[0][0]
        assert "Additional context info" in call_args

    def test_includes_current_knowledge_in_prompt(self):
        """Test that current knowledge is included in prompt."""
        from local_deep_research.advanced_search_system.knowledge.standard_knowledge import (
            StandardKnowledge,
        )

        mock_model = Mock()
        mock_model.invoke.return_value = Mock(content="Knowledge")

        knowledge = StandardKnowledge(mock_model)
        knowledge.generate_knowledge(
            "Query", current_knowledge="Previous findings"
        )

        call_args = mock_model.invoke.call_args[0][0]
        assert "Previous findings" in call_args

    def test_includes_questions_when_provided(self):
        """Test that questions are included when provided."""
        from local_deep_research.advanced_search_system.knowledge.standard_knowledge import (
            StandardKnowledge,
        )

        mock_model = Mock()
        mock_model.invoke.return_value = Mock(content="Knowledge")

        knowledge = StandardKnowledge(mock_model)
        questions = ["Question 1?", "Question 2?"]
        knowledge.generate_knowledge("Query", questions=questions)

        call_args = mock_model.invoke.call_args[0][0]
        assert "Question 1?" in call_args or "Questions:" in call_args

    def test_uses_different_prompt_without_questions(self):
        """Test that different prompt is used when no questions."""
        from local_deep_research.advanced_search_system.knowledge.standard_knowledge import (
            StandardKnowledge,
        )

        mock_model = Mock()
        mock_model.invoke.return_value = Mock(content="Knowledge")

        knowledge = StandardKnowledge(mock_model)
        knowledge.generate_knowledge("Query", questions=None)

        call_args = mock_model.invoke.call_args[0][0]
        # Should not mention "Addresses each question"
        assert "Addresses each question" not in call_args


class TestGenerateSubKnowledge:
    """Tests for generate_sub_knowledge method."""

    def test_generates_sub_knowledge(self):
        """Test generating knowledge for sub-question."""
        from local_deep_research.advanced_search_system.knowledge.standard_knowledge import (
            StandardKnowledge,
        )

        mock_model = Mock()
        mock_model.invoke.return_value = Mock(content="Sub-knowledge")

        knowledge = StandardKnowledge(mock_model)
        result = knowledge.generate_sub_knowledge("What is the sub-question?")

        assert result == "Sub-knowledge"

    def test_includes_sub_query_in_prompt(self):
        """Test that sub-query is included in prompt."""
        from local_deep_research.advanced_search_system.knowledge.standard_knowledge import (
            StandardKnowledge,
        )

        mock_model = Mock()
        mock_model.invoke.return_value = Mock(content="Knowledge")

        knowledge = StandardKnowledge(mock_model)
        knowledge.generate_sub_knowledge("Specific sub-question about topic")

        call_args = mock_model.invoke.call_args[0][0]
        assert "Specific sub-question about topic" in call_args

    def test_includes_context_in_sub_knowledge(self):
        """Test that context is included in sub-knowledge prompt."""
        from local_deep_research.advanced_search_system.knowledge.standard_knowledge import (
            StandardKnowledge,
        )

        mock_model = Mock()
        mock_model.invoke.return_value = Mock(content="Knowledge")

        knowledge = StandardKnowledge(mock_model)
        knowledge.generate_sub_knowledge("Sub-query", context="Context for sub")

        call_args = mock_model.invoke.call_args[0][0]
        assert "Context for sub" in call_args

    def test_handles_exception(self):
        """Test that exceptions are handled gracefully."""
        from local_deep_research.advanced_search_system.knowledge.standard_knowledge import (
            StandardKnowledge,
        )

        mock_model = Mock()
        mock_model.invoke.side_effect = Exception("Model error")

        knowledge = StandardKnowledge(mock_model)
        result = knowledge.generate_sub_knowledge("Query")

        assert result == ""


class TestGenerate:
    """Tests for generate method."""

    def test_delegates_to_generate_knowledge(self):
        """Test that generate delegates to generate_knowledge."""
        from local_deep_research.advanced_search_system.knowledge.standard_knowledge import (
            StandardKnowledge,
        )

        mock_model = Mock()
        mock_model.invoke.return_value = Mock(content="Generated")

        knowledge = StandardKnowledge(mock_model)
        result = knowledge.generate("Query", "Context")

        assert result == "Generated"


class TestCompressKnowledge:
    """Tests for compress_knowledge method."""

    def test_compresses_knowledge(self):
        """Test compressing accumulated knowledge."""
        from local_deep_research.advanced_search_system.knowledge.standard_knowledge import (
            StandardKnowledge,
        )

        mock_model = Mock()
        mock_model.invoke.return_value = Mock(content="Compressed knowledge")

        knowledge = StandardKnowledge(mock_model)
        result = knowledge.compress_knowledge(
            current_knowledge="Long accumulated knowledge...",
            query="Original query",
            section_links=["link1", "link2"],
        )

        assert result == "Compressed knowledge"

    def test_includes_query_in_compression_prompt(self):
        """Test that query is included in compression prompt."""
        from local_deep_research.advanced_search_system.knowledge.standard_knowledge import (
            StandardKnowledge,
        )

        mock_model = Mock()
        mock_model.invoke.return_value = Mock(content="Compressed")

        knowledge = StandardKnowledge(mock_model)
        knowledge.compress_knowledge(
            current_knowledge="Knowledge",
            query="Test query for compression",
            section_links=[],
        )

        call_args = mock_model.invoke.call_args[0][0]
        assert "Test query for compression" in call_args

    def test_includes_knowledge_in_compression_prompt(self):
        """Test that knowledge is included in compression prompt."""
        from local_deep_research.advanced_search_system.knowledge.standard_knowledge import (
            StandardKnowledge,
        )

        mock_model = Mock()
        mock_model.invoke.return_value = Mock(content="Compressed")

        knowledge = StandardKnowledge(mock_model)
        knowledge.compress_knowledge(
            current_knowledge="Important accumulated findings here",
            query="Query",
            section_links=[],
        )

        call_args = mock_model.invoke.call_args[0][0]
        assert "Important accumulated findings here" in call_args

    def test_handles_compression_exception(self):
        """Test that compression exception returns original knowledge."""
        from local_deep_research.advanced_search_system.knowledge.standard_knowledge import (
            StandardKnowledge,
        )

        mock_model = Mock()
        mock_model.invoke.side_effect = Exception("Compression error")

        knowledge = StandardKnowledge(mock_model)
        result = knowledge.compress_knowledge(
            current_knowledge="Original knowledge",
            query="Query",
            section_links=[],
        )

        # Should return original when compression fails
        assert result == "Original knowledge"


class TestFormatCitations:
    """Tests for format_citations method."""

    def test_formats_citations_ieee_style(self):
        """Test formatting citations in IEEE style."""
        from local_deep_research.advanced_search_system.knowledge.standard_knowledge import (
            StandardKnowledge,
        )

        knowledge = StandardKnowledge(Mock())
        links = ["https://example.com/1", "https://example.com/2"]

        result = knowledge.format_citations(links)

        assert "[1] https://example.com/1" in result
        assert "[2] https://example.com/2" in result

    def test_returns_empty_for_empty_links(self):
        """Test that empty string is returned for empty links."""
        from local_deep_research.advanced_search_system.knowledge.standard_knowledge import (
            StandardKnowledge,
        )

        knowledge = StandardKnowledge(Mock())

        result = knowledge.format_citations([])

        assert result == ""

    def test_handles_single_link(self):
        """Test formatting a single link."""
        from local_deep_research.advanced_search_system.knowledge.standard_knowledge import (
            StandardKnowledge,
        )

        knowledge = StandardKnowledge(Mock())
        links = ["https://example.com/single"]

        result = knowledge.format_citations(links)

        assert "[1] https://example.com/single" in result
        assert "[2]" not in result

    def test_citations_are_newline_separated(self):
        """Test that citations are newline separated."""
        from local_deep_research.advanced_search_system.knowledge.standard_knowledge import (
            StandardKnowledge,
        )

        knowledge = StandardKnowledge(Mock())
        links = ["link1", "link2", "link3"]

        result = knowledge.format_citations(links)

        assert result.count("\n") == 2
