"""
Comprehensive tests for TopicBasedRecommender class.
Tests recommendation generation, topic filtering, and user preferences.
"""

from unittest.mock import Mock, patch


class TestTopicBasedRecommenderInit:
    """Tests for TopicBasedRecommender initialization."""

    def test_inherits_from_base(self):
        """Test inherits from BaseRecommender."""
        from local_deep_research.news.recommender.topic_based import (
            TopicBasedRecommender,
        )
        from local_deep_research.news.recommender.base_recommender import (
            BaseRecommender,
        )

        assert issubclass(TopicBasedRecommender, BaseRecommender)

    def test_default_max_recommendations(self):
        """Test default max_recommendations is 5."""
        from local_deep_research.news.recommender.topic_based import (
            TopicBasedRecommender,
        )

        recommender = TopicBasedRecommender()
        assert recommender.max_recommendations == 5


class TestGenerateRecommendations:
    """Tests for generate_recommendations method."""

    @patch.object(
        __import__(
            "local_deep_research.news.recommender.topic_based",
            fromlist=["TopicBasedRecommender"],
        ).TopicBasedRecommender,
        "_get_trending_topics",
    )
    @patch.object(
        __import__(
            "local_deep_research.news.recommender.topic_based",
            fromlist=["TopicBasedRecommender"],
        ).TopicBasedRecommender,
        "_get_user_preferences",
    )
    @patch.object(
        __import__(
            "local_deep_research.news.recommender.topic_based",
            fromlist=["TopicBasedRecommender"],
        ).TopicBasedRecommender,
        "_filter_topics_by_preferences",
    )
    @patch.object(
        __import__(
            "local_deep_research.news.recommender.topic_based",
            fromlist=["TopicBasedRecommender"],
        ).TopicBasedRecommender,
        "_sort_by_relevance",
    )
    def test_returns_list(
        self, mock_sort, mock_filter, mock_prefs, mock_topics
    ):
        """Test returns a list."""
        from local_deep_research.news.recommender.topic_based import (
            TopicBasedRecommender,
        )

        mock_topics.return_value = []
        mock_prefs.return_value = {}
        mock_filter.return_value = []
        mock_sort.return_value = []

        recommender = TopicBasedRecommender()
        result = recommender.generate_recommendations("user123")

        assert isinstance(result, list)

    @patch.object(
        __import__(
            "local_deep_research.news.recommender.topic_based",
            fromlist=["TopicBasedRecommender"],
        ).TopicBasedRecommender,
        "_get_trending_topics",
    )
    def test_updates_progress(self, mock_topics):
        """Test updates progress during generation."""
        from local_deep_research.news.recommender.topic_based import (
            TopicBasedRecommender,
        )

        mock_topics.return_value = []

        recommender = TopicBasedRecommender()
        recommender._update_progress = Mock()

        with patch.object(
            recommender, "_get_user_preferences", return_value={}
        ):
            with patch.object(
                recommender, "_filter_topics_by_preferences", return_value=[]
            ):
                with patch.object(
                    recommender, "_sort_by_relevance", return_value=[]
                ):
                    recommender.generate_recommendations("user123")

        recommender._update_progress.assert_called()

    @patch.object(
        __import__(
            "local_deep_research.news.recommender.topic_based",
            fromlist=["TopicBasedRecommender"],
        ).TopicBasedRecommender,
        "_get_trending_topics",
    )
    def test_handles_exception(self, mock_topics):
        """Test handles exception gracefully."""
        from local_deep_research.news.recommender.topic_based import (
            TopicBasedRecommender,
        )

        mock_topics.side_effect = Exception("Error getting topics")

        recommender = TopicBasedRecommender()
        result = recommender.generate_recommendations("user123")

        assert result == []


class TestGetTrendingTopics:
    """Tests for _get_trending_topics method."""

    def test_returns_list(self):
        """Test returns a list."""
        from local_deep_research.news.recommender.topic_based import (
            TopicBasedRecommender,
        )

        recommender = TopicBasedRecommender()
        result = recommender._get_trending_topics(None)

        assert isinstance(result, list)

    def test_returns_fallback_topics_when_empty(self):
        """Test returns fallback topics when no topics found."""
        from local_deep_research.news.recommender.topic_based import (
            TopicBasedRecommender,
        )

        recommender = TopicBasedRecommender()
        recommender.topic_registry = None  # No registry

        result = recommender._get_trending_topics(None)

        assert len(result) > 0  # Should have fallback topics

    def test_uses_topic_registry_when_available(self):
        """Test uses topic registry when available."""
        from local_deep_research.news.recommender.topic_based import (
            TopicBasedRecommender,
        )

        mock_registry = Mock()
        mock_registry.get_trending_topics.return_value = ["AI", "Climate"]

        recommender = TopicBasedRecommender()
        recommender.topic_registry = mock_registry

        result = recommender._get_trending_topics(None)

        assert "AI" in result
        assert "Climate" in result

    def test_adds_context_topics(self):
        """Test adds topics from context."""
        from local_deep_research.news.recommender.topic_based import (
            TopicBasedRecommender,
        )

        recommender = TopicBasedRecommender()

        context = {"current_news_topics": ["Blockchain"]}
        result = recommender._get_trending_topics(context)

        assert "Blockchain" in result


class TestFilterTopicsByPreferences:
    """Tests for _filter_topics_by_preferences method."""

    def test_returns_list(self):
        """Test returns a list."""
        from local_deep_research.news.recommender.topic_based import (
            TopicBasedRecommender,
        )

        recommender = TopicBasedRecommender()
        result = recommender._filter_topics_by_preferences(["AI", "Sports"], {})

        assert isinstance(result, list)

    def test_filters_disliked_topics(self):
        """Test filters out disliked topics."""
        from local_deep_research.news.recommender.topic_based import (
            TopicBasedRecommender,
        )

        recommender = TopicBasedRecommender()
        preferences = {"disliked_topics": ["Sports"]}

        result = recommender._filter_topics_by_preferences(
            ["AI", "Sports", "Tech"], preferences
        )

        assert "Sports" not in result

    def test_preserves_non_disliked_topics(self):
        """Test preserves non-disliked topics."""
        from local_deep_research.news.recommender.topic_based import (
            TopicBasedRecommender,
        )

        recommender = TopicBasedRecommender()
        preferences = {"disliked_topics": ["Sports"]}

        result = recommender._filter_topics_by_preferences(
            ["AI", "Sports", "Tech"], preferences
        )

        assert "AI" in result
        assert "Tech" in result


class TestGenerateTopicQuery:
    """Tests for _generate_topic_query method."""

    def test_returns_string(self):
        """Test returns a string."""
        from local_deep_research.news.recommender.topic_based import (
            TopicBasedRecommender,
        )

        recommender = TopicBasedRecommender()
        result = recommender._generate_topic_query("artificial intelligence")

        assert isinstance(result, str)

    def test_includes_topic(self):
        """Test query includes the topic."""
        from local_deep_research.news.recommender.topic_based import (
            TopicBasedRecommender,
        )

        recommender = TopicBasedRecommender()
        result = recommender._generate_topic_query("blockchain")

        assert "blockchain" in result.lower()


class TestCreateRecommendationCard:
    """Tests for _create_recommendation_card method."""

    @patch("local_deep_research.news.recommender.topic_based.CardFactory")
    def test_returns_card_or_none(self, mock_factory):
        """Test returns card or None."""
        from local_deep_research.news.recommender.topic_based import (
            TopicBasedRecommender,
        )

        recommender = TopicBasedRecommender()

        result = recommender._create_recommendation_card(
            "AI", "AI news today", "user123"
        )

        # May return None or card depending on implementation
        assert result is None or hasattr(result, "topic")


class TestSortByRelevance:
    """Tests for _sort_by_relevance method."""

    def test_returns_list(self):
        """Test returns a list."""
        from local_deep_research.news.recommender.topic_based import (
            TopicBasedRecommender,
        )

        recommender = TopicBasedRecommender()
        result = recommender._sort_by_relevance([], "user123")

        assert isinstance(result, list)

    def test_preserves_cards(self):
        """Test preserves all cards in output."""
        from local_deep_research.news.recommender.topic_based import (
            TopicBasedRecommender,
        )

        # Mock cards with required attributes for sorting
        mock_cards = [
            Mock(impact_score=5.0, category="tech", metadata={}),
            Mock(impact_score=8.0, category="news", metadata={}),
            Mock(impact_score=3.0, category="science", metadata={}),
        ]

        recommender = TopicBasedRecommender()
        result = recommender._sort_by_relevance(mock_cards, "user123")

        assert len(result) == len(mock_cards)


class TestTopicBasedRecommenderWithContext:
    """Tests for recommendations with various contexts."""

    def test_handles_empty_context(self):
        """Test handles empty context dict."""
        from local_deep_research.news.recommender.topic_based import (
            TopicBasedRecommender,
        )

        recommender = TopicBasedRecommender()

        with patch.object(
            recommender, "_get_trending_topics", return_value=["AI"]
        ) as mock_topics:
            with patch.object(
                recommender, "_get_user_preferences", return_value={}
            ):
                with patch.object(
                    recommender,
                    "_filter_topics_by_preferences",
                    return_value=[],
                ):
                    with patch.object(
                        recommender, "_sort_by_relevance", return_value=[]
                    ):
                        recommender.generate_recommendations(
                            "user123", context={}
                        )

        mock_topics.assert_called_once_with({})

    def test_handles_none_context(self):
        """Test handles None context."""
        from local_deep_research.news.recommender.topic_based import (
            TopicBasedRecommender,
        )

        recommender = TopicBasedRecommender()

        with patch.object(
            recommender, "_get_trending_topics", return_value=["AI"]
        ) as mock_topics:
            with patch.object(
                recommender, "_get_user_preferences", return_value={}
            ):
                with patch.object(
                    recommender,
                    "_filter_topics_by_preferences",
                    return_value=[],
                ):
                    with patch.object(
                        recommender, "_sort_by_relevance", return_value=[]
                    ):
                        recommender.generate_recommendations(
                            "user123", context=None
                        )

        mock_topics.assert_called_once_with(None)


class TestTopicBasedRecommenderEdgeCases:
    """Edge case tests for TopicBasedRecommender."""

    def test_handles_no_topics(self):
        """Test handles case with no topics."""
        from local_deep_research.news.recommender.topic_based import (
            TopicBasedRecommender,
        )

        recommender = TopicBasedRecommender()

        with patch.object(recommender, "_get_trending_topics", return_value=[]):
            with patch.object(
                recommender, "_get_user_preferences", return_value={}
            ):
                with patch.object(
                    recommender,
                    "_filter_topics_by_preferences",
                    return_value=[],
                ):
                    with patch.object(
                        recommender, "_sort_by_relevance", return_value=[]
                    ):
                        result = recommender.generate_recommendations("user123")

        assert result == []

    def test_limits_recommendations(self):
        """Test limits recommendations to max_recommendations."""
        from local_deep_research.news.recommender.topic_based import (
            TopicBasedRecommender,
        )

        recommender = TopicBasedRecommender()
        recommender.max_recommendations = 3

        with patch.object(
            recommender,
            "_get_trending_topics",
            return_value=["A", "B", "C", "D", "E"],
        ):
            with patch.object(
                recommender, "_get_user_preferences", return_value={}
            ):
                with patch.object(
                    recommender,
                    "_filter_topics_by_preferences",
                    return_value=["A", "B", "C", "D", "E"],
                ):
                    with patch.object(
                        recommender,
                        "_create_recommendation_card",
                        return_value=None,
                    ):
                        with patch.object(
                            recommender, "_sort_by_relevance", return_value=[]
                        ):
                            recommender.generate_recommendations("user123")

        # Implementation should only process max_recommendations topics


class TestTopicBasedRecommenderImports:
    """Tests for module imports."""

    def test_imports_topic_based_recommender(self):
        """Test TopicBasedRecommender can be imported."""
        from local_deep_research.news.recommender.topic_based import (
            TopicBasedRecommender,
        )

        assert TopicBasedRecommender is not None

    def test_is_class(self):
        """Test TopicBasedRecommender is a class."""
        from local_deep_research.news.recommender.topic_based import (
            TopicBasedRecommender,
        )

        assert isinstance(TopicBasedRecommender, type)
