"""High-value pure logic tests for FindingsRepository and format_links."""

from unittest.mock import MagicMock, patch

from langchain_core.documents import Document


class TestFormatLinks:
    """Tests for the standalone format_links function."""

    def test_single_link(self):
        from local_deep_research.advanced_search_system.findings.repository import (
            format_links,
        )

        links = [{"title": "Example", "url": "https://example.com"}]
        result = format_links(links)
        assert "1. Example" in result
        assert "URL: https://example.com" in result

    def test_multiple_links_numbered_sequentially(self):
        from local_deep_research.advanced_search_system.findings.repository import (
            format_links,
        )

        links = [
            {"title": "First", "url": "https://first.com"},
            {"title": "Second", "url": "https://second.com"},
            {"title": "Third", "url": "https://third.com"},
        ]
        result = format_links(links)
        assert "1. First" in result
        assert "2. Second" in result
        assert "3. Third" in result

    def test_empty_links_list(self):
        from local_deep_research.advanced_search_system.findings.repository import (
            format_links,
        )

        result = format_links([])
        assert result == ""

    def test_link_format_structure(self):
        from local_deep_research.advanced_search_system.findings.repository import (
            format_links,
        )

        links = [{"title": "Test", "url": "https://test.com"}]
        result = format_links(links)
        lines = result.split("\n")
        assert lines[0] == "1. Test"
        assert lines[1] == "   URL: https://test.com"

    def test_links_with_special_characters_in_title(self):
        from local_deep_research.advanced_search_system.findings.repository import (
            format_links,
        )

        links = [
            {
                "title": 'Title & <Special> "Chars"',
                "url": "https://example.com/path?q=1&r=2",
            }
        ]
        result = format_links(links)
        assert 'Title & <Special> "Chars"' in result
        assert "https://example.com/path?q=1&r=2" in result


def _make_repo():
    """Create a FindingsRepository with a mocked model, bypassing parent init side effects."""
    mock_model = MagicMock()
    with patch(
        "local_deep_research.advanced_search_system.findings.repository.BaseFindingsRepository.__init__",
        return_value=None,
    ):
        from local_deep_research.advanced_search_system.findings.repository import (
            FindingsRepository,
        )

        repo = FindingsRepository(mock_model)
    return repo


class TestAddFinding:
    """Tests for FindingsRepository.add_finding()."""

    def test_add_string_finding_converts_to_dict(self):
        repo = _make_repo()
        repo.add_finding("query1", "some content")
        findings = repo.get_findings("query1")
        assert len(findings) == 1
        assert findings[0]["content"] == "some content"
        assert findings[0]["phase"] == "Synthesis"
        assert findings[0]["question"] == "query1"
        assert findings[0]["search_results"] == []
        assert findings[0]["documents"] == []

    def test_add_dict_finding_stored_as_is(self):
        repo = _make_repo()
        finding = {"phase": "Research", "content": "data", "extra": 42}
        repo.add_finding("q", finding)
        assert repo.get_findings("q") == [finding]

    def test_add_final_synthesis_creates_synthesis_key(self):
        repo = _make_repo()
        finding = {"phase": "Final synthesis", "content": "final answer"}
        repo.add_finding("q", finding)
        # Original query should have the finding
        assert len(repo.get_findings("q")) == 1
        # Synthesis key should also exist
        synthesis = repo.get_findings("q_synthesis")
        assert len(synthesis) == 1
        assert synthesis[0]["phase"] == "Synthesis"
        assert synthesis[0]["content"] == "final answer"

    def test_add_non_final_synthesis_dict_no_synthesis_key(self):
        repo = _make_repo()
        finding = {"phase": "Intermediate", "content": "partial"}
        repo.add_finding("q", finding)
        assert repo.get_findings("q_synthesis") == []

    def test_add_multiple_findings_same_query(self):
        repo = _make_repo()
        repo.add_finding("q", "first")
        repo.add_finding("q", "second")
        repo.add_finding("q", "third")
        assert len(repo.get_findings("q")) == 3

    def test_add_findings_different_queries(self):
        repo = _make_repo()
        repo.add_finding("q1", "a")
        repo.add_finding("q2", "b")
        assert len(repo.get_findings("q1")) == 1
        assert len(repo.get_findings("q2")) == 1

    def test_final_synthesis_with_missing_content_key(self):
        repo = _make_repo()
        finding = {"phase": "Final synthesis"}
        repo.add_finding("q", finding)
        synthesis = repo.get_findings("q_synthesis")
        assert synthesis[0]["content"] == ""

    def test_final_synthesis_overwrites_previous_synthesis_key(self):
        repo = _make_repo()
        repo.add_finding("q", {"phase": "Final synthesis", "content": "v1"})
        repo.add_finding("q", {"phase": "Final synthesis", "content": "v2"})
        synthesis = repo.get_findings("q_synthesis")
        # Second final synthesis replaces the list
        assert len(synthesis) == 1
        assert synthesis[0]["content"] == "v2"


class TestGetFindings:
    """Tests for FindingsRepository.get_findings()."""

    def test_get_findings_nonexistent_query_returns_empty(self):
        repo = _make_repo()
        assert repo.get_findings("nonexistent") == []

    def test_get_findings_returns_correct_data(self):
        repo = _make_repo()
        repo.add_finding("q", "content")
        findings = repo.get_findings("q")
        assert len(findings) == 1
        assert findings[0]["content"] == "content"

    def test_get_findings_returns_mutable_reference(self):
        repo = _make_repo()
        repo.add_finding("q", "data")
        findings = repo.get_findings("q")
        findings.append({"extra": True})
        # Since it returns the actual list, mutation is reflected
        assert len(repo.get_findings("q")) == 2


class TestClearFindings:
    """Tests for FindingsRepository.clear_findings()."""

    def test_clear_existing_findings(self):
        repo = _make_repo()
        repo.add_finding("q", "data")
        repo.clear_findings("q")
        assert repo.get_findings("q") == []

    def test_clear_nonexistent_query_no_error(self):
        repo = _make_repo()
        # Should not raise
        repo.clear_findings("nonexistent")

    def test_clear_does_not_affect_other_queries(self):
        repo = _make_repo()
        repo.add_finding("q1", "a")
        repo.add_finding("q2", "b")
        repo.clear_findings("q1")
        assert repo.get_findings("q1") == []
        assert len(repo.get_findings("q2")) == 1


class TestAddDocuments:
    """Tests for FindingsRepository.add_documents()."""

    def test_add_documents_extends_list(self):
        repo = _make_repo()
        docs = [Document(page_content="doc1"), Document(page_content="doc2")]
        repo.add_documents(docs)
        assert len(repo.documents) == 2

    def test_add_documents_multiple_calls_accumulate(self):
        repo = _make_repo()
        repo.add_documents([Document(page_content="a")])
        repo.add_documents(
            [Document(page_content="b"), Document(page_content="c")]
        )
        assert len(repo.documents) == 3

    def test_add_empty_documents_list(self):
        repo = _make_repo()
        repo.add_documents([])
        assert len(repo.documents) == 0


class TestSetQuestionsByIteration:
    """Tests for FindingsRepository.set_questions_by_iteration()."""

    def test_set_questions_stores_data(self):
        repo = _make_repo()
        questions = {1: ["q1", "q2"], 2: ["q3"]}
        repo.set_questions_by_iteration(questions)
        assert repo.questions_by_iteration == {1: ["q1", "q2"], 2: ["q3"]}

    def test_set_questions_copies_input(self):
        repo = _make_repo()
        questions = {1: ["q1"]}
        repo.set_questions_by_iteration(questions)
        # Mutating the original should not affect stored data
        questions[2] = ["q2"]
        assert 2 not in repo.questions_by_iteration

    def test_set_questions_overwrites_previous(self):
        repo = _make_repo()
        repo.set_questions_by_iteration({1: ["old"]})
        repo.set_questions_by_iteration({1: ["new"], 2: ["extra"]})
        assert repo.questions_by_iteration == {1: ["new"], 2: ["extra"]}

    def test_set_empty_questions(self):
        repo = _make_repo()
        repo.set_questions_by_iteration({})
        assert repo.questions_by_iteration == {}
