"""
Deep coverage tests for FindingsRepository (beyond synthesize_findings).

Tests cover missing branches in:
- add_finding: string finding converted to dict; dict finding appended directly;
  dict with phase "Final synthesis" creates _synthesis key
- get_findings: known query returns list; unknown query returns empty list
- clear_findings: deletes existing key; no-op on unknown key
- add_documents: appends to self.documents
- set_questions_by_iteration: copies dict into self.questions_by_iteration
- format_findings_to_text: success path calls format_findings; exception path returns fallback
"""

from unittest.mock import MagicMock, patch

from local_deep_research.advanced_search_system.findings.repository import (
    FindingsRepository,
    format_links,
)

MODULE = "local_deep_research.advanced_search_system.findings.repository"


# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------


def _make_repo():
    model = MagicMock()
    return FindingsRepository(model=model)


# ---------------------------------------------------------------------------
# format_links (standalone utility)
# ---------------------------------------------------------------------------


class TestFormatLinks:
    """format_links formats a list of link dicts into numbered strings."""

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

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

    def test_empty_list_returns_empty_string(self):
        assert format_links([]) == ""


# ---------------------------------------------------------------------------
# add_finding
# ---------------------------------------------------------------------------


class TestAddFinding:
    """add_finding converts strings and handles dicts."""

    def test_string_finding_converted_to_dict(self):
        repo = _make_repo()
        repo.add_finding("query", "some text finding")

        findings = repo.get_findings("query")
        assert len(findings) == 1
        assert findings[0]["content"] == "some text finding"
        assert findings[0]["phase"] == "Synthesis"
        assert findings[0]["question"] == "query"

    def test_dict_finding_appended_directly(self):
        repo = _make_repo()
        finding = {"phase": "Custom", "content": "custom content"}
        repo.add_finding("query", finding)

        findings = repo.get_findings("query")
        assert len(findings) == 1
        assert findings[0] is finding

    def test_final_synthesis_creates_synthesis_key(self):
        repo = _make_repo()
        finding = {"phase": "Final synthesis", "content": "final answer"}
        repo.add_finding("query", finding)

        # The synthesis key should also be stored
        synthesis_findings = repo.get_findings("query_synthesis")
        assert len(synthesis_findings) == 1
        assert synthesis_findings[0]["content"] == "final answer"

    def test_multiple_findings_accumulated(self):
        repo = _make_repo()
        repo.add_finding("query", "first")
        repo.add_finding("query", "second")
        assert len(repo.get_findings("query")) == 2


# ---------------------------------------------------------------------------
# get_findings
# ---------------------------------------------------------------------------


class TestGetFindings:
    """get_findings returns list for known queries, empty list for unknown."""

    def test_known_query_returns_list(self):
        repo = _make_repo()
        repo.add_finding("q", "content")
        assert len(repo.get_findings("q")) == 1

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


# ---------------------------------------------------------------------------
# clear_findings
# ---------------------------------------------------------------------------


class TestClearFindings:
    """clear_findings removes key; no-op for missing key."""

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

    def test_clear_missing_query_does_not_raise(self):
        repo = _make_repo()
        # Should not raise
        repo.clear_findings("does_not_exist")


# ---------------------------------------------------------------------------
# add_documents
# ---------------------------------------------------------------------------


class TestAddDocuments:
    """add_documents appends documents to self.documents."""

    def test_documents_appended(self):
        from langchain_core.documents import Document

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

    def test_multiple_calls_accumulate(self):
        from langchain_core.documents import Document

        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


# ---------------------------------------------------------------------------
# set_questions_by_iteration
# ---------------------------------------------------------------------------


class TestSetQuestionsByIteration:
    """set_questions_by_iteration copies the dict."""

    def test_stores_copy_of_dict(self):
        repo = _make_repo()
        original = {1: ["q1"], 2: ["q2"]}
        repo.set_questions_by_iteration(original)

        assert repo.questions_by_iteration == original

    def test_mutation_does_not_affect_repo(self):
        """Stored copy is independent of original dict."""
        repo = _make_repo()
        original = {1: ["q1"]}
        repo.set_questions_by_iteration(original)
        original[1] = ["mutated"]

        assert repo.questions_by_iteration[1] == ["q1"]


# ---------------------------------------------------------------------------
# format_findings_to_text
# ---------------------------------------------------------------------------


class TestFormatFindingsToText:
    """format_findings_to_text success and error paths."""

    def test_success_calls_format_findings_and_returns(self):
        repo = _make_repo()
        repo.questions_by_iteration = {1: ["q1"]}

        with patch(
            f"{MODULE}.format_findings", return_value="formatted report"
        ) as mock_ff:
            result = repo.format_findings_to_text(
                findings_list=[{"content": "data", "phase": "P1"}],
                synthesized_content="synthesis here",
            )

        assert result == "formatted report"
        mock_ff.assert_called_once()

    def test_exception_returns_fallback_message(self):
        repo = _make_repo()
        repo.questions_by_iteration = {}

        with patch(f"{MODULE}.format_findings", side_effect=Exception("boom")):
            result = repo.format_findings_to_text(
                findings_list=[{"content": "data"}],
                synthesized_content="synthesis",
            )

        assert "Error" in result
        assert "synthesis" in result
