"""
Tests for utilities/search_utilities.py - None Safety and Edge Cases

Tests cover:
- remove_think_tags edge cases
- Link formatting with None values
- Edge cases that could cause AttributeError crashes in production

These tests focus on defensive programming and graceful error handling.
"""


class TestRemoveThinkTagsEdgeCases:
    """Tests for edge cases in remove_think_tags function."""

    def test_nested_think_tags(self):
        """<think><think>inner</think></think> handled."""
        from local_deep_research.utilities.search_utilities import (
            remove_think_tags,
        )

        text = "Start <think>outer<think>inner</think>outer</think> End"
        result = remove_think_tags(text)

        # Inner tags should be removed first, then outer
        # The regex is non-greedy, so it removes the innermost first
        assert "<think>" not in result
        assert "</think>" not in result
        assert "Start" in result
        assert "End" in result

    def test_think_tags_with_attributes(self):
        """<think class='x'> still removed."""
        from local_deep_research.utilities.search_utilities import (
            remove_think_tags,
        )

        # The current regex uses <think> exactly, not <think.*?>
        # So attributes might not be removed
        text = "Hello <think class='internal'>content</think> world"
        result = remove_think_tags(text)

        # Check if it's removed (depends on implementation)
        # The current implementation uses exact <think> match
        # This test documents current behavior
        assert "Hello" in result  # Input is still processed

    def test_think_tags_case_variations(self):
        """<THINK>, <Think> behavior documented."""
        from local_deep_research.utilities.search_utilities import (
            remove_think_tags,
        )

        # Test uppercase
        text_upper = "Hello <THINK>content</THINK> world"
        result_upper = remove_think_tags(text_upper)

        # The regex doesn't use re.IGNORECASE, so uppercase might not match
        # This documents the current behavior
        assert "Hello" in result_upper

        # Test mixed case
        text_mixed = "Hello <Think>content</Think> world"
        result_mixed = remove_think_tags(text_mixed)
        assert "Hello" in result_mixed

    def test_unclosed_think_tag_at_end(self):
        """Text ending with unclosed tag."""
        from local_deep_research.utilities.search_utilities import (
            remove_think_tags,
        )

        text = "Hello world <think>unclosed content"
        result = remove_think_tags(text)

        # Orphaned opening tag should be removed
        assert "<think>" not in result
        assert "Hello world" in result

    def test_empty_think_tags(self):
        """<think></think> removed cleanly."""
        from local_deep_research.utilities.search_utilities import (
            remove_think_tags,
        )

        text = "Before <think></think> After"
        result = remove_think_tags(text)

        assert "<think>" not in result
        assert "</think>" not in result
        assert "Before" in result
        assert "After" in result

    def test_orphaned_closing_tags(self):
        """</think> without opening."""
        from local_deep_research.utilities.search_utilities import (
            remove_think_tags,
        )

        text = "Some content </think> more content"
        result = remove_think_tags(text)

        assert "</think>" not in result
        assert "Some content" in result
        assert "more content" in result

    def test_think_tags_in_code_blocks(self):
        """Tags in markdown code preserved."""
        from local_deep_research.utilities.search_utilities import (
            remove_think_tags,
        )

        # The current implementation doesn't distinguish code blocks
        # This documents the behavior
        text = "```python\n# <think>comment</think>\nprint('hello')\n```"
        result = remove_think_tags(text)

        # The think tag will still be removed even in code
        # This is the current behavior
        assert "print('hello')" in result

    def test_think_tag_spanning_newlines(self):
        """Multi-line think content."""
        from local_deep_research.utilities.search_utilities import (
            remove_think_tags,
        )

        text = """Start
<think>
Line 1
Line 2
Line 3
</think>
End"""
        result = remove_think_tags(text)

        assert "Start" in result
        assert "End" in result
        assert "Line 1" not in result
        assert "Line 2" not in result


class TestLinkFormattingNoneSafety:
    """Tests for None safety in link formatting functions."""

    def test_none_url_skipped(self):
        """Link with url=None skipped."""
        from local_deep_research.utilities.search_utilities import (
            format_links_to_markdown,
        )

        links = [
            {"title": "Valid", "url": "http://valid.com", "index": "1"},
            {"title": "No URL", "url": None, "index": "2"},
            {"title": "Also Valid", "url": "http://also.com", "index": "3"},
        ]

        result = format_links_to_markdown(links)

        assert "valid.com" in result
        assert "also.com" in result
        # None URL should be skipped, not cause error

    def test_none_link_key_skipped(self):
        """Link with link=None skipped."""
        from local_deep_research.utilities.search_utilities import (
            format_links_to_markdown,
        )

        links = [
            {"title": "Valid", "link": "http://valid.com", "index": "1"},
            {"title": "No Link", "link": None, "index": "2"},
        ]

        result = format_links_to_markdown(links)

        assert "valid.com" in result

    def test_none_title_uses_untitled(self):
        """None title becomes 'Untitled' via get default."""
        from local_deep_research.utilities.search_utilities import (
            format_links_to_markdown,
        )

        # When title key is missing, it uses "Untitled" default
        links = [{"url": "http://example.com", "index": "1"}]  # No title key

        result = format_links_to_markdown(links)

        # Should use default title
        assert "Untitled" in result
        assert "example.com" in result

    def test_none_index_handled(self):
        """None index doesn't crash."""
        from local_deep_research.utilities.search_utilities import (
            format_links_to_markdown,
        )

        links = [{"title": "Test", "url": "http://test.com", "index": None}]

        # Should not crash
        result = format_links_to_markdown(links)

        assert "test.com" in result

    def test_all_none_values_skipped(self):
        """All-None link dict skipped."""
        from local_deep_research.utilities.search_utilities import (
            format_links_to_markdown,
        )

        links = [
            {"title": None, "url": None, "index": None},
            {"title": "Valid", "url": "http://valid.com", "index": "1"},
        ]

        result = format_links_to_markdown(links)

        # First link should be skipped
        assert "valid.com" in result

    def test_mixed_none_values(self):
        """Some None, some valid values."""
        from local_deep_research.utilities.search_utilities import (
            format_links_to_markdown,
        )

        links = [
            {"title": "Has Title", "url": None, "index": "1"},  # No URL - skip
            {
                "title": None,
                "url": "http://has-url.com",
                "index": "2",
            },  # No title - use Untitled
            {
                "title": "Complete",
                "url": "http://complete.com",
                "index": None,
            },  # No index
        ]

        result = format_links_to_markdown(links)

        # Link with no URL should be skipped
        # Link with no title should have "Untitled"
        assert "has-url.com" in result
        assert "complete.com" in result

    def test_indices_sorted_and_deduped(self):
        """[3,1,1,5] becomes [1,3,5]."""
        from local_deep_research.utilities.search_utilities import (
            format_links_to_markdown,
        )

        links = [
            {"title": "Same", "url": "http://same.com", "index": "3"},
            {"title": "Same", "url": "http://same.com", "index": "1"},
            {
                "title": "Same",
                "url": "http://same.com",
                "index": "1",
            },  # Duplicate
            {"title": "Same", "url": "http://same.com", "index": "5"},
        ]

        result = format_links_to_markdown(links)

        # URL should appear only once (deduplicated)
        assert result.count("same.com") == 1

        # Indices should be sorted and deduped: [1, 3, 5]
        assert "[1, 3, 5]" in result


class TestExtractLinksNoneSafety:
    """Tests for None safety in extract_links_from_search_results."""

    def test_none_values_in_search_results(self):
        """Handle None values in result dicts."""
        from local_deep_research.utilities.search_utilities import (
            extract_links_from_search_results,
        )

        results = [
            {"title": "Valid", "link": "http://valid.com", "index": "1"},
            {"title": None, "link": "http://notitle.com", "index": "2"},
            {"title": "No Link", "link": None, "index": "3"},
            {"title": None, "link": None, "index": None},
        ]

        links = extract_links_from_search_results(results)

        # Only fully valid links should be included
        valid_urls = [link["url"] for link in links]
        assert "http://valid.com" in valid_urls

    def test_missing_keys_in_search_results(self):
        """Handle missing keys in result dicts."""
        from local_deep_research.utilities.search_utilities import (
            extract_links_from_search_results,
        )

        results = [
            {"title": "Valid", "link": "http://valid.com"},  # No index
            {"link": "http://notitle.com"},  # No title
            {"title": "No Link"},  # No link
            {},  # Empty dict
        ]

        links = extract_links_from_search_results(results)

        # Should not crash, should extract what it can
        assert isinstance(links, list)

    def test_whitespace_only_values(self):
        """Handle whitespace-only strings."""
        from local_deep_research.utilities.search_utilities import (
            extract_links_from_search_results,
        )

        results = [
            {"title": "   ", "link": "http://valid.com", "index": "1"},
            {"title": "Valid", "link": "   ", "index": "2"},
        ]

        links = extract_links_from_search_results(results)

        # Whitespace-only values should be treated as empty
        # After strip(), "" is falsy, so these should be skipped
        assert isinstance(links, list)

    def test_empty_string_values(self):
        """Handle empty string values."""
        from local_deep_research.utilities.search_utilities import (
            extract_links_from_search_results,
        )

        results = [
            {"title": "", "link": "http://valid.com", "index": "1"},
            {"title": "Valid", "link": "", "index": "2"},
        ]

        links = extract_links_from_search_results(results)

        # Empty strings should result in skipped links
        assert isinstance(links, list)


class TestFormatFindingsEdgeCases:
    """Tests for edge cases in format_findings function."""

    def test_empty_findings_list(self):
        """Empty findings list doesn't crash."""
        from local_deep_research.utilities.search_utilities import (
            format_findings,
        )

        result = format_findings([], "Synthesized content", {})

        assert "Synthesized content" in result

    def test_none_values_in_findings(self):
        """None values in findings handled."""
        from local_deep_research.utilities.search_utilities import (
            format_findings,
        )

        findings = [
            {
                "phase": None,
                "content": "Has content",
                "search_results": None,
            },
            {
                "phase": "Has phase",
                "content": None,
                "search_results": [],
            },
        ]

        # Should not crash
        result = format_findings(findings, "Summary", {})

        assert "Summary" in result

    def test_missing_keys_in_findings(self):
        """Missing keys in findings handled."""
        from local_deep_research.utilities.search_utilities import (
            format_findings,
        )

        findings = [
            {"phase": "Only Phase"},  # No content or search_results
            {"content": "Only Content"},  # No phase or search_results
            {},  # Empty dict
        ]

        # Should not crash, should use defaults
        result = format_findings(findings, "Summary", {})

        assert "Summary" in result

    def test_followup_phase_parsing_edge_cases(self):
        """Edge cases in Follow-up phase parsing."""
        from local_deep_research.utilities.search_utilities import (
            format_findings,
        )

        findings = [
            {
                "phase": "Follow-up Iteration .1",  # Invalid format
                "content": "Content 1",
                "search_results": [],
            },
            {
                "phase": "Follow-up Iteration abc.def",  # Non-numeric
                "content": "Content 2",
                "search_results": [],
            },
            {
                "phase": "Follow-up Iteration 1.99",  # Out of range index
                "content": "Content 3",
                "search_results": [],
            },
        ]

        questions = {1: ["Question 1"]}

        # Should not crash on invalid formats
        result = format_findings(findings, "Summary", questions)

        assert "Summary" in result

    def test_subquery_phase_parsing_edge_cases(self):
        """Edge cases in Sub-query phase parsing."""
        from local_deep_research.utilities.search_utilities import (
            format_findings,
        )

        findings = [
            {
                "phase": "Sub-query ",  # Missing number
                "content": "Content 1",
                "search_results": [],
            },
            {
                "phase": "Sub-query abc",  # Non-numeric
                "content": "Content 2",
                "search_results": [],
            },
            {
                "phase": "Sub-query 999",  # Out of range
                "content": "Content 3",
                "search_results": [],
            },
        ]

        questions = {0: ["Question 1", "Question 2"]}

        # Should not crash on invalid formats
        result = format_findings(findings, "Summary", questions)

        assert "Summary" in result


class TestLanguageCodeMapSafety:
    """Tests for LANGUAGE_CODE_MAP constant."""

    def test_lowercase_keys(self):
        """All keys are lowercase."""
        from local_deep_research.utilities.search_utilities import (
            LANGUAGE_CODE_MAP,
        )

        for key in LANGUAGE_CODE_MAP:
            assert key == key.lower()

    def test_two_letter_values(self):
        """All values are two-letter codes."""
        from local_deep_research.utilities.search_utilities import (
            LANGUAGE_CODE_MAP,
        )

        for code in LANGUAGE_CODE_MAP.values():
            assert len(code) == 2
