"""
Extended tests for news/utils/headline_generator.py

Tests cover:
- generate_headline() function
- _generate_with_llm() helper
- Headline cleaning and validation
- LLM integration error handling
- Edge cases with various inputs
"""

from unittest.mock import Mock, patch


class TestGenerateHeadlineBasic:
    """Basic tests for generate_headline() function."""

    def test_returns_string(self):
        """generate_headline returns a string."""
        with patch(
            "local_deep_research.news.utils.headline_generator._generate_with_llm"
        ) as mock_gen:
            mock_gen.return_value = "Test Headline"

            from local_deep_research.news.utils.headline_generator import (
                generate_headline,
            )

            result = generate_headline("test query", "test findings")

            assert isinstance(result, str)

    def test_uses_llm_generated_headline(self):
        """Uses LLM-generated headline when available."""
        with patch(
            "local_deep_research.news.utils.headline_generator._generate_with_llm"
        ) as mock_gen:
            mock_gen.return_value = "LLM Generated Headline"

            from local_deep_research.news.utils.headline_generator import (
                generate_headline,
            )

            result = generate_headline("query", "findings")

            assert result == "LLM Generated Headline"

    def test_returns_failure_message_when_llm_fails(self):
        """Returns failure message when LLM fails."""
        with patch(
            "local_deep_research.news.utils.headline_generator._generate_with_llm"
        ) as mock_gen:
            mock_gen.return_value = None

            from local_deep_research.news.utils.headline_generator import (
                generate_headline,
            )

            result = generate_headline("query", "findings")

            assert "[Headline generation failed]" in result

    def test_accepts_empty_findings(self):
        """Accepts empty findings parameter."""
        with patch(
            "local_deep_research.news.utils.headline_generator._generate_with_llm"
        ) as mock_gen:
            mock_gen.return_value = None

            from local_deep_research.news.utils.headline_generator import (
                generate_headline,
            )

            # Should not raise
            result = generate_headline("query", "")

            assert isinstance(result, str)

    def test_accepts_max_length_parameter(self):
        """Accepts max_length parameter."""
        with patch(
            "local_deep_research.news.utils.headline_generator._generate_with_llm"
        ) as mock_gen:
            mock_gen.return_value = "Short headline"

            from local_deep_research.news.utils.headline_generator import (
                generate_headline,
            )

            generate_headline("query", "findings", max_length=50)

            # generate_headline now threads settings_snapshot (defaults
            # to None) into _generate_with_llm so background news jobs
            # can hand the egress policy to get_llm.
            mock_gen.assert_called_once_with("query", "findings", 50, None)


class TestGenerateWithLLM:
    """Tests for _generate_with_llm() helper."""

    def test_returns_none_without_findings(self):
        """Returns None when no findings provided."""
        from local_deep_research.news.utils.headline_generator import (
            _generate_with_llm,
        )

        result = _generate_with_llm("query", "", 100)

        assert result is None

    def test_function_signature(self):
        """Function has correct signature."""
        from local_deep_research.news.utils.headline_generator import (
            _generate_with_llm,
        )

        # Should accept query, findings, max_length
        assert callable(_generate_with_llm)

    def test_calls_llm_with_findings(self):
        """When the LLM returns content, _generate_with_llm strips the
        text and returns the resulting string (it does not return the
        raw LangChain response object)."""
        with patch(
            "local_deep_research.config.llm_config.get_llm"
        ) as mock_get_llm:
            mock_llm = Mock()
            mock_llm.invoke.return_value = Mock(content="Test Headline")
            mock_get_llm.return_value = mock_llm

            from local_deep_research.news.utils.headline_generator import (
                _generate_with_llm,
            )

            result = _generate_with_llm("query", "Some findings", 100)

            assert result == "Test Headline"

    def test_returns_none_on_llm_import_error(self):
        """Returns None when LLM import fails."""
        from local_deep_research.news.utils.headline_generator import (
            _generate_with_llm,
        )

        with patch.dict(
            "sys.modules", {"local_deep_research.config.llm_config": None}
        ):
            # Import error should be caught
            result = _generate_with_llm("query", "findings", 100)

            # Either returns a headline or None, should not crash
            assert result is None or isinstance(result, str)


class TestHeadlineEdgeCases:
    """Edge case tests for headline generation."""

    def test_empty_query(self):
        """Handles empty query."""
        with patch(
            "local_deep_research.news.utils.headline_generator._generate_with_llm"
        ) as mock_gen:
            mock_gen.return_value = "Generated Headline"

            from local_deep_research.news.utils.headline_generator import (
                generate_headline,
            )

            result = generate_headline("", "some findings")

            assert isinstance(result, str)

    def test_unicode_query(self):
        """Handles unicode in query."""
        with patch(
            "local_deep_research.news.utils.headline_generator._generate_with_llm"
        ) as mock_gen:
            mock_gen.return_value = "日本語ヘッドライン"

            from local_deep_research.news.utils.headline_generator import (
                generate_headline,
            )

            result = generate_headline("日本語クエリ", "findings")

            assert "日本語" in result

    def test_very_long_query(self):
        """Handles very long query."""
        with patch(
            "local_deep_research.news.utils.headline_generator._generate_with_llm"
        ) as mock_gen:
            mock_gen.return_value = "Short Headline"

            from local_deep_research.news.utils.headline_generator import (
                generate_headline,
            )

            long_query = "x" * 10000
            result = generate_headline(long_query, "findings")

            assert isinstance(result, str)

    def test_special_characters_in_query(self):
        """Handles special characters in query."""
        with patch(
            "local_deep_research.news.utils.headline_generator._generate_with_llm"
        ) as mock_gen:
            mock_gen.return_value = "Tech Headline"

            from local_deep_research.news.utils.headline_generator import (
                generate_headline,
            )

            result = generate_headline("C++ & Python <> news", "findings")

            assert isinstance(result, str)


class TestGenerateHeadlineIntegration:
    """Integration tests for generate_headline."""

    def test_full_flow_returns_string(self):
        """Full flow returns a string."""
        with patch(
            "local_deep_research.news.utils.headline_generator._generate_with_llm"
        ) as mock_gen:
            mock_gen.return_value = "Breaking News"

            from local_deep_research.news.utils.headline_generator import (
                generate_headline,
            )

            result = generate_headline("query", "findings")

            assert isinstance(result, str)

    def test_full_flow_with_none_from_llm(self):
        """Full flow when LLM returns None."""
        with patch(
            "local_deep_research.news.utils.headline_generator._generate_with_llm"
        ) as mock_gen:
            mock_gen.return_value = None

            from local_deep_research.news.utils.headline_generator import (
                generate_headline,
            )

            result = generate_headline("query", "findings")

            assert "failed" in result.lower()


class TestHeadlineValidation:
    """Tests for headline validation logic."""

    def test_preserves_valid_content(self):
        """Preserves valid headline content."""
        with patch(
            "local_deep_research.news.utils.headline_generator._generate_with_llm"
        ) as mock_gen:
            mock_gen.return_value = "COVID-19: New Variant Detected"

            from local_deep_research.news.utils.headline_generator import (
                generate_headline,
            )

            result = generate_headline("query", "findings")

            assert "COVID-19" in result

    def test_preserves_semicolons(self):
        """Preserves semicolons in multi-part headlines."""
        with patch(
            "local_deep_research.news.utils.headline_generator._generate_with_llm"
        ) as mock_gen:
            mock_gen.return_value = "First Event; Second Event"

            from local_deep_research.news.utils.headline_generator import (
                generate_headline,
            )

            result = generate_headline("query", "findings")

            assert ";" in result

    def test_preserves_numbers(self):
        """Preserves numbers in headlines."""
        with patch(
            "local_deep_research.news.utils.headline_generator._generate_with_llm"
        ) as mock_gen:
            mock_gen.return_value = "500 Affected in Event"

            from local_deep_research.news.utils.headline_generator import (
                generate_headline,
            )

            result = generate_headline("query", "findings")

            assert "500" in result
