"""
Tests for advanced_search_system/findings/topic.py

Tests cover:
- Topic dataclass
- TopicGraph class
- Source management
- Topic relationships
"""


class TestTopicDataclass:
    """Tests for Topic dataclass."""

    def test_init_with_required_fields(self):
        """Test initialization with required fields."""
        from local_deep_research.advanced_search_system.findings.topic import (
            Topic,
        )

        topic = Topic(
            id="topic_1",
            title="Test Topic",
            lead_source={"title": "Lead Source", "url": "http://example.com"},
        )

        assert topic.id == "topic_1"
        assert topic.title == "Test Topic"
        assert topic.lead_source["title"] == "Lead Source"

    def test_init_defaults_empty_lists(self):
        """Test that lists default to empty."""
        from local_deep_research.advanced_search_system.findings.topic import (
            Topic,
        )

        topic = Topic(
            id="topic_1",
            title="Test Topic",
            lead_source={"title": "Lead"},
        )

        assert topic.supporting_sources == []
        assert topic.rejected_sources == []
        assert topic.related_topic_ids == []
        assert topic.child_topic_ids == []

    def test_init_with_supporting_sources(self):
        """Test initialization with supporting sources."""
        from local_deep_research.advanced_search_system.findings.topic import (
            Topic,
        )

        supporting = [{"title": "Support 1"}, {"title": "Support 2"}]
        topic = Topic(
            id="topic_1",
            title="Test Topic",
            lead_source={"title": "Lead"},
            supporting_sources=supporting,
        )

        assert len(topic.supporting_sources) == 2

    def test_parent_topic_id_defaults_none(self):
        """Test that parent_topic_id defaults to None."""
        from local_deep_research.advanced_search_system.findings.topic import (
            Topic,
        )

        topic = Topic(
            id="topic_1",
            title="Test Topic",
            lead_source={"title": "Lead"},
        )

        assert topic.parent_topic_id is None


class TestTopicMethods:
    """Tests for Topic methods."""

    def test_add_supporting_source(self):
        """Test adding a supporting source."""
        from local_deep_research.advanced_search_system.findings.topic import (
            Topic,
        )

        topic = Topic(
            id="topic_1",
            title="Test Topic",
            lead_source={"title": "Lead"},
        )

        source = {"title": "New Source"}
        topic.add_supporting_source(source)

        assert source in topic.supporting_sources

    def test_add_supporting_source_no_duplicates(self):
        """Test that duplicate sources are not added."""
        from local_deep_research.advanced_search_system.findings.topic import (
            Topic,
        )

        source = {"title": "Source"}
        topic = Topic(
            id="topic_1",
            title="Test Topic",
            lead_source={"title": "Lead"},
            supporting_sources=[source],
        )

        topic.add_supporting_source(source)

        assert topic.supporting_sources.count(source) == 1

    def test_reject_source(self):
        """Test rejecting a source."""
        from local_deep_research.advanced_search_system.findings.topic import (
            Topic,
        )

        source = {"title": "Source"}
        topic = Topic(
            id="topic_1",
            title="Test Topic",
            lead_source={"title": "Lead"},
            supporting_sources=[source],
        )

        topic.reject_source(source)

        assert source not in topic.supporting_sources
        assert source in topic.rejected_sources

    def test_reject_source_no_duplicates(self):
        """Test that rejected sources are not duplicated."""
        from local_deep_research.advanced_search_system.findings.topic import (
            Topic,
        )

        source = {"title": "Source"}
        topic = Topic(
            id="topic_1",
            title="Test Topic",
            lead_source={"title": "Lead"},
            rejected_sources=[source],
        )

        topic.reject_source(source)

        assert topic.rejected_sources.count(source) == 1

    def test_update_lead_source(self):
        """Test updating lead source."""
        from local_deep_research.advanced_search_system.findings.topic import (
            Topic,
        )

        old_lead = {"title": "Old Lead"}
        new_lead = {"title": "New Lead"}
        topic = Topic(
            id="topic_1",
            title="Test Topic",
            lead_source=old_lead,
        )

        topic.update_lead_source(new_lead)

        assert topic.lead_source == new_lead
        assert old_lead in topic.supporting_sources

    def test_update_lead_source_removes_from_supporting(self):
        """Test that new lead is removed from supporting sources."""
        from local_deep_research.advanced_search_system.findings.topic import (
            Topic,
        )

        new_lead = {"title": "New Lead"}
        topic = Topic(
            id="topic_1",
            title="Test Topic",
            lead_source={"title": "Old Lead"},
            supporting_sources=[new_lead, {"title": "Other"}],
        )

        topic.update_lead_source(new_lead)

        assert new_lead not in topic.supporting_sources
        assert topic.lead_source == new_lead

    def test_get_all_sources(self):
        """Test getting all sources."""
        from local_deep_research.advanced_search_system.findings.topic import (
            Topic,
        )

        lead = {"title": "Lead"}
        supporting = [{"title": "Support 1"}, {"title": "Support 2"}]
        topic = Topic(
            id="topic_1",
            title="Test Topic",
            lead_source=lead,
            supporting_sources=supporting,
        )

        all_sources = topic.get_all_sources()

        assert len(all_sources) == 3
        assert lead in all_sources
        assert all(s in all_sources for s in supporting)

    def test_to_dict(self):
        """Test converting topic to dictionary."""
        from local_deep_research.advanced_search_system.findings.topic import (
            Topic,
        )

        topic = Topic(
            id="topic_1",
            title="Test Topic",
            lead_source={"title": "Lead"},
            related_topic_ids=["topic_2"],
        )

        result = topic.to_dict()

        assert result["id"] == "topic_1"
        assert result["title"] == "Test Topic"
        assert result["lead_source"]["title"] == "Lead"
        assert "topic_2" in result["related_topic_ids"]
        assert "created_at" in result


class TestTopicGraph:
    """Tests for TopicGraph class."""

    def test_init_creates_empty_topics(self):
        """Test that initialization creates empty topics dict."""
        from local_deep_research.advanced_search_system.findings.topic import (
            TopicGraph,
        )

        graph = TopicGraph()

        assert graph.topics == {}

    def test_add_topic(self):
        """Test adding a topic to the graph."""
        from local_deep_research.advanced_search_system.findings.topic import (
            Topic,
            TopicGraph,
        )

        graph = TopicGraph()
        topic = Topic(id="t1", title="Test", lead_source={"title": "Lead"})

        graph.add_topic(topic)

        assert "t1" in graph.topics
        assert graph.topics["t1"] is topic

    def test_get_topic(self):
        """Test getting a topic by ID."""
        from local_deep_research.advanced_search_system.findings.topic import (
            Topic,
            TopicGraph,
        )

        graph = TopicGraph()
        topic = Topic(id="t1", title="Test", lead_source={"title": "Lead"})
        graph.add_topic(topic)

        result = graph.get_topic("t1")

        assert result is topic

    def test_get_topic_not_found(self):
        """Test getting a non-existent topic."""
        from local_deep_research.advanced_search_system.findings.topic import (
            TopicGraph,
        )

        graph = TopicGraph()

        result = graph.get_topic("nonexistent")

        assert result is None

    def test_link_topics(self):
        """Test linking two topics."""
        from local_deep_research.advanced_search_system.findings.topic import (
            Topic,
            TopicGraph,
        )

        graph = TopicGraph()
        topic1 = Topic(id="t1", title="Topic 1", lead_source={"title": "Lead"})
        topic2 = Topic(id="t2", title="Topic 2", lead_source={"title": "Lead"})
        graph.add_topic(topic1)
        graph.add_topic(topic2)

        graph.link_topics("t1", "t2")

        assert "t2" in topic1.related_topic_ids
        assert "t1" in topic2.related_topic_ids

    def test_link_topics_no_duplicates(self):
        """Test that linking topics doesn't create duplicates."""
        from local_deep_research.advanced_search_system.findings.topic import (
            Topic,
            TopicGraph,
        )

        graph = TopicGraph()
        topic1 = Topic(id="t1", title="Topic 1", lead_source={"title": "Lead"})
        topic2 = Topic(id="t2", title="Topic 2", lead_source={"title": "Lead"})
        graph.add_topic(topic1)
        graph.add_topic(topic2)

        graph.link_topics("t1", "t2")
        graph.link_topics("t1", "t2")

        assert topic1.related_topic_ids.count("t2") == 1

    def test_set_parent_child(self):
        """Test setting parent-child relationship."""
        from local_deep_research.advanced_search_system.findings.topic import (
            Topic,
            TopicGraph,
        )

        graph = TopicGraph()
        parent = Topic(
            id="parent", title="Parent", lead_source={"title": "Lead"}
        )
        child = Topic(id="child", title="Child", lead_source={"title": "Lead"})
        graph.add_topic(parent)
        graph.add_topic(child)

        graph.set_parent_child("parent", "child")

        assert "child" in parent.child_topic_ids
        assert child.parent_topic_id == "parent"

    def test_get_root_topics(self):
        """Test getting root topics (no parent)."""
        from local_deep_research.advanced_search_system.findings.topic import (
            Topic,
            TopicGraph,
        )

        graph = TopicGraph()
        root1 = Topic(id="root1", title="Root 1", lead_source={"title": "Lead"})
        root2 = Topic(id="root2", title="Root 2", lead_source={"title": "Lead"})
        child = Topic(id="child", title="Child", lead_source={"title": "Lead"})
        graph.add_topic(root1)
        graph.add_topic(root2)
        graph.add_topic(child)
        graph.set_parent_child("root1", "child")

        roots = graph.get_root_topics()

        assert len(roots) == 2
        assert root1 in roots
        assert root2 in roots
        assert child not in roots

    def test_get_related_topics(self):
        """Test getting related topics."""
        from local_deep_research.advanced_search_system.findings.topic import (
            Topic,
            TopicGraph,
        )

        graph = TopicGraph()
        topic1 = Topic(id="t1", title="Topic 1", lead_source={"title": "Lead"})
        topic2 = Topic(id="t2", title="Topic 2", lead_source={"title": "Lead"})
        topic3 = Topic(id="t3", title="Topic 3", lead_source={"title": "Lead"})
        graph.add_topic(topic1)
        graph.add_topic(topic2)
        graph.add_topic(topic3)
        graph.link_topics("t1", "t2")
        graph.link_topics("t1", "t3")

        related = graph.get_related_topics("t1")

        assert len(related) == 2
        assert topic2 in related
        assert topic3 in related

    def test_get_related_topics_nonexistent(self):
        """Test getting related topics for non-existent topic."""
        from local_deep_research.advanced_search_system.findings.topic import (
            TopicGraph,
        )

        graph = TopicGraph()

        related = graph.get_related_topics("nonexistent")

        assert related == []


class TestTopicGraphMerge:
    """Tests for TopicGraph merge functionality."""

    def test_merge_topics(self):
        """Test merging two topics."""
        from local_deep_research.advanced_search_system.findings.topic import (
            Topic,
            TopicGraph,
        )

        graph = TopicGraph()
        topic1 = Topic(
            id="t1",
            title="Topic 1",
            lead_source={"title": "Lead 1"},
            supporting_sources=[{"title": "Support 1"}],
        )
        topic2 = Topic(
            id="t2",
            title="Topic 2",
            lead_source={"title": "Lead 2"},
            supporting_sources=[{"title": "Support 2"}],
        )
        graph.add_topic(topic1)
        graph.add_topic(topic2)

        merged = graph.merge_topics("t1", "t2")

        assert merged is topic1
        assert "t2" not in graph.topics
        assert len(topic1.supporting_sources) >= 2

    def test_merge_topics_with_new_title(self):
        """Test merging topics with new title."""
        from local_deep_research.advanced_search_system.findings.topic import (
            Topic,
            TopicGraph,
        )

        graph = TopicGraph()
        topic1 = Topic(
            id="t1", title="Old Title", lead_source={"title": "Lead"}
        )
        topic2 = Topic(id="t2", title="Topic 2", lead_source={"title": "Lead"})
        graph.add_topic(topic1)
        graph.add_topic(topic2)

        merged = graph.merge_topics("t1", "t2", new_title="Merged Topic")

        assert merged.title == "Merged Topic"

    def test_merge_topics_nonexistent(self):
        """Test merging with non-existent topic."""
        from local_deep_research.advanced_search_system.findings.topic import (
            Topic,
            TopicGraph,
        )

        graph = TopicGraph()
        topic1 = Topic(id="t1", title="Topic 1", lead_source={"title": "Lead"})
        graph.add_topic(topic1)

        result = graph.merge_topics("t1", "nonexistent")

        assert result is None

    def test_merge_updates_references(self):
        """Test that merge updates references in other topics."""
        from local_deep_research.advanced_search_system.findings.topic import (
            Topic,
            TopicGraph,
        )

        graph = TopicGraph()
        topic1 = Topic(id="t1", title="Topic 1", lead_source={"title": "Lead"})
        topic2 = Topic(id="t2", title="Topic 2", lead_source={"title": "Lead"})
        topic3 = Topic(id="t3", title="Topic 3", lead_source={"title": "Lead"})
        graph.add_topic(topic1)
        graph.add_topic(topic2)
        graph.add_topic(topic3)
        graph.link_topics("t2", "t3")

        graph.merge_topics("t1", "t2")

        # topic3 should now be related to t1 instead of t2
        assert "t2" not in topic3.related_topic_ids
        assert "t1" in topic3.related_topic_ids


class TestTopicGraphToDict:
    """Tests for TopicGraph.to_dict method."""

    def test_to_dict_empty_graph(self):
        """Test converting empty graph to dict."""
        from local_deep_research.advanced_search_system.findings.topic import (
            TopicGraph,
        )

        graph = TopicGraph()

        result = graph.to_dict()

        assert result == {}

    def test_to_dict_with_topics(self):
        """Test converting graph with topics to dict."""
        from local_deep_research.advanced_search_system.findings.topic import (
            Topic,
            TopicGraph,
        )

        graph = TopicGraph()
        topic1 = Topic(id="t1", title="Topic 1", lead_source={"title": "Lead"})
        topic2 = Topic(id="t2", title="Topic 2", lead_source={"title": "Lead"})
        graph.add_topic(topic1)
        graph.add_topic(topic2)

        result = graph.to_dict()

        assert "t1" in result
        assert "t2" in result
        assert result["t1"]["title"] == "Topic 1"
        assert result["t2"]["title"] == "Topic 2"
