"""
Comprehensive tests for topic_generator module.
Tests topic extraction with LLM integration, validation, and edge cases.
"""

from unittest.mock import patch


class TestGenerateTopics:
    """Tests for generate_topics function."""

    @patch("local_deep_research.news.utils.topic_generator._generate_with_llm")
    @patch("local_deep_research.news.utils.topic_generator._validate_topics")
    def test_returns_validated_topics(self, mock_validate, mock_llm_gen):
        """Test returns validated topics from LLM."""
        from local_deep_research.news.utils.topic_generator import (
            generate_topics,
        )

        mock_llm_gen.return_value = ["AI", "Technology", "Research"]
        mock_validate.return_value = ["ai", "technology", "research"]

        result = generate_topics("AI news", findings="Content")

        assert result == ["ai", "technology", "research"]

    @patch("local_deep_research.news.utils.topic_generator._generate_with_llm")
    @patch("local_deep_research.news.utils.topic_generator._validate_topics")
    def test_returns_failure_marker_when_llm_fails(
        self, mock_validate, mock_llm_gen
    ):
        """Test returns failure marker when LLM returns empty."""
        from local_deep_research.news.utils.topic_generator import (
            generate_topics,
        )

        mock_llm_gen.return_value = []
        mock_validate.return_value = ["[topic generation failed]"]

        _ = generate_topics("query", findings="data")

        mock_validate.assert_called_once()
        call_args = mock_validate.call_args[0]
        assert call_args[0] == ["[Topic generation failed]"]

    @patch("local_deep_research.news.utils.topic_generator._generate_with_llm")
    @patch("local_deep_research.news.utils.topic_generator._validate_topics")
    def test_passes_max_topics_to_validator(self, mock_validate, mock_llm_gen):
        """Test passes max_topics to validator."""
        from local_deep_research.news.utils.topic_generator import (
            generate_topics,
        )

        mock_llm_gen.return_value = ["A", "B"]
        mock_validate.return_value = ["a", "b"]

        generate_topics("query", max_topics=3)

        mock_validate.assert_called_once()
        assert mock_validate.call_args[0][1] == 3

    @patch("local_deep_research.news.utils.topic_generator._generate_with_llm")
    @patch("local_deep_research.news.utils.topic_generator._validate_topics")
    def test_default_max_topics_is_5(self, mock_validate, mock_llm_gen):
        """Test default max_topics is 5."""
        from local_deep_research.news.utils.topic_generator import (
            generate_topics,
        )

        mock_llm_gen.return_value = []
        mock_validate.return_value = []

        generate_topics("query")

        mock_llm_gen.assert_called_once()
        # Fourth argument is max_topics
        assert mock_llm_gen.call_args[0][3] == 5

    @patch("local_deep_research.news.utils.topic_generator._generate_with_llm")
    @patch("local_deep_research.news.utils.topic_generator._validate_topics")
    def test_passes_category_to_llm(self, mock_validate, mock_llm_gen):
        """Test passes category to LLM generator."""
        from local_deep_research.news.utils.topic_generator import (
            generate_topics,
        )

        mock_llm_gen.return_value = []
        mock_validate.return_value = []

        generate_topics("query", category="Technology")

        assert mock_llm_gen.call_args[0][2] == "Technology"


class TestGenerateWithLLMTopicsBehavior:
    """Tests for _generate_with_llm behavior."""

    def test_function_exists_and_is_callable(self):
        """Test _generate_with_llm function exists and is callable."""
        from local_deep_research.news.utils.topic_generator import (
            _generate_with_llm,
        )

        assert callable(_generate_with_llm)

    def test_accepts_four_parameters(self):
        """Test accepts query, findings, category, and max_topics parameters."""
        from local_deep_research.news.utils.topic_generator import (
            _generate_with_llm,
        )
        import inspect

        sig = inspect.signature(_generate_with_llm)
        params = list(sig.parameters.keys())

        # Now accepts settings_snapshot for egress-policy threading.
        assert len(params) == 5
        assert "settings_snapshot" in params
        assert "query" in params
        assert "findings" in params
        assert "category" in params
        assert "max_topics" in params

    def test_returns_list(self):
        """Test returns a list (empty or with topics)."""
        from local_deep_research.news.utils.topic_generator import (
            _generate_with_llm,
        )

        # Without proper LLM setup, may return empty list
        result = _generate_with_llm("query", "", "", 5)

        assert isinstance(result, list)


class TestValidateTopics:
    """Tests for _validate_topics function."""

    def test_returns_list(self):
        """Test returns a list."""
        from local_deep_research.news.utils.topic_generator import (
            _validate_topics,
        )

        result = _validate_topics(["AI", "Tech"], 5)

        assert isinstance(result, list)

    def test_removes_empty_topics(self):
        """Test removes empty string topics."""
        from local_deep_research.news.utils.topic_generator import (
            _validate_topics,
        )

        result = _validate_topics(["AI", "", "Tech", ""], 5)

        assert "" not in result

    def test_removes_whitespace_only_topics(self):
        """Test removes whitespace-only topics."""
        from local_deep_research.news.utils.topic_generator import (
            _validate_topics,
        )

        result = _validate_topics(["AI", "   ", "Tech"], 5)

        assert len([t for t in result if t.strip() == ""]) == 0

    def test_removes_too_short_topics(self):
        """Test removes topics shorter than 2 characters."""
        from local_deep_research.news.utils.topic_generator import (
            _validate_topics,
        )

        result = _validate_topics(["A", "AI", "Tech"], 5)

        assert "A" not in result or len("A") >= 2  # Single char removed

    def test_removes_too_long_topics(self):
        """Test removes topics longer than 30 characters."""
        from local_deep_research.news.utils.topic_generator import (
            _validate_topics,
        )

        long_topic = "A" * 35
        result = _validate_topics(["AI", long_topic, "Tech"], 5)

        assert long_topic not in result

    def test_removes_duplicates_case_insensitive(self):
        """Test removes duplicates case-insensitively."""
        from local_deep_research.news.utils.topic_generator import (
            _validate_topics,
        )

        result = _validate_topics(["AI", "ai", "Ai"], 5)

        assert len(result) == 1

    def test_limits_to_max_topics(self):
        """Test limits output to max_topics."""
        from local_deep_research.news.utils.topic_generator import (
            _validate_topics,
        )

        topics = ["AI", "Tech", "Science", "News", "Research", "Data"]
        result = _validate_topics(topics, 3)

        assert len(result) <= 3

    def test_converts_to_lowercase(self):
        """Test converts topics to lowercase."""
        from local_deep_research.news.utils.topic_generator import (
            _validate_topics,
        )

        result = _validate_topics(["UPPERCASE", "MixedCase"], 5)

        assert all(t == t.lower() for t in result if t != "[No valid topics]")

    def test_returns_no_valid_marker_when_empty(self):
        """Test returns marker when no valid topics."""
        from local_deep_research.news.utils.topic_generator import (
            _validate_topics,
        )

        result = _validate_topics([], 5)

        assert result == ["[No valid topics]"]

    def test_returns_no_valid_marker_when_all_invalid(self):
        """Test returns marker when all topics are invalid."""
        from local_deep_research.news.utils.topic_generator import (
            _validate_topics,
        )

        result = _validate_topics(["", "A", "B" * 50], 5)

        assert result == ["[No valid topics]"]


class TestTopicGeneratorEdgeCases:
    """Edge case tests for topic generator."""

    @patch("local_deep_research.news.utils.topic_generator._generate_with_llm")
    @patch("local_deep_research.news.utils.topic_generator._validate_topics")
    def test_handles_unicode_topics(self, mock_validate, mock_llm_gen):
        """Test handles unicode characters in topics."""
        from local_deep_research.news.utils.topic_generator import (
            generate_topics,
        )

        mock_llm_gen.return_value = ["日本", "テクノロジー"]
        mock_validate.return_value = ["日本", "テクノロジー"]

        result = generate_topics("Japanese tech news")

        assert result == ["日本", "テクノロジー"]

    def test_validate_topics_handles_mixed_types(self):
        """Test _validate_topics handles mixed types."""
        from local_deep_research.news.utils.topic_generator import (
            _validate_topics,
        )

        # Validate handles valid strings
        result = _validate_topics(["AI", "Tech", "Science"], 5)

        assert isinstance(result, list)
        assert all(isinstance(t, str) for t in result)

    def test_generate_topics_returns_list_for_empty_input(self):
        """Test generate_topics returns list for empty input."""
        from local_deep_research.news.utils.topic_generator import (
            generate_topics,
        )

        # With empty inputs, should return failure marker
        result = generate_topics("")

        assert isinstance(result, list)

    def test_validate_topics_handles_none_input(self):
        """Test _validate_topics handles None input gracefully."""
        from local_deep_research.news.utils.topic_generator import (
            _validate_topics,
        )

        # If topics is None, function should handle it
        try:
            _ = _validate_topics(None, 5)
            # Should return failure marker or handle gracefully
        except (TypeError, AttributeError):
            # This is acceptable - None input may raise
            pass

    @patch("local_deep_research.news.utils.topic_generator._generate_with_llm")
    @patch("local_deep_research.news.utils.topic_generator._validate_topics")
    def test_zero_max_topics(self, mock_validate, mock_llm_gen):
        """Test handles zero max_topics."""
        from local_deep_research.news.utils.topic_generator import (
            generate_topics,
        )

        mock_llm_gen.return_value = []
        mock_validate.return_value = []

        result = generate_topics("query", max_topics=0)

        assert isinstance(result, list)


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

    def test_imports_generate_topics(self):
        """Test generate_topics can be imported."""
        from local_deep_research.news.utils.topic_generator import (
            generate_topics,
        )

        assert generate_topics is not None
        assert callable(generate_topics)

    def test_imports_validate_topics(self):
        """Test _validate_topics can be imported."""
        from local_deep_research.news.utils.topic_generator import (
            _validate_topics,
        )

        assert _validate_topics is not None
        assert callable(_validate_topics)

    def test_imports_generate_with_llm(self):
        """Test _generate_with_llm can be imported."""
        from local_deep_research.news.utils.topic_generator import (
            _generate_with_llm,
        )

        assert _generate_with_llm is not None
        assert callable(_generate_with_llm)
