"""Tests for real-world LLM output patterns that extract_json encounters in production.

These tests document edge cases observed in actual LLM responses that aren't
covered by the basic test_json_utils.py tests.
"""

from local_deep_research.utilities.json_utils import (
    extract_json,
    get_llm_response_text,
)


class TestMultipleCodeFences:
    """Tests for LLM responses containing multiple code fences."""

    def test_multiple_json_code_fences_uses_first(self):
        """When an LLM self-corrects by producing two ```json blocks,
        _strip_code_fences uses the first one. This documents the behavior
        since it could arguably pick either."""
        text = (
            "Let me try:\n"
            '```json\n{"answer": "first attempt"}\n```\n'
            "Wait, let me correct that:\n"
            '```json\n{"answer": "corrected"}\n```'
        )
        result = extract_json(text)
        # Documents current behavior: first ```json block wins
        assert result == {"answer": "first attempt"}

    def test_non_json_language_tag_code_fence(self):
        """A ```python fence doesn't match ```json, so it falls through
        to the bare ``` path which extracts between the first pair of ```."""
        text = (
            "Here is the data:\n"
            '```python\ndata = {"key": "value"}\n```\n'
            "That's it."
        )
        result = extract_json(text)
        # The bare ``` path extracts: 'python\ndata = {"key": "value"}'
        # Then bracket extraction finds {"key": "value"} inside
        assert result == {"key": "value"}


class TestUrlsAndCommentRegex:
    """Tests for interaction between URLs in JSON values and the // comment removal regex."""

    def test_malformed_json_with_urls_comment_regex_interaction(self):
        """When JSON has a trailing comma (triggering artifact cleaning),
        the // comment-removal regex strips everything after // in URLs.
        This documents a known limitation."""
        text = '{"url": "https://example.com/page", "count": 1,}'
        result = extract_json(text)
        # The trailing comma makes direct parse fail.
        # Artifact cleaning: removes trailing comma AND removes "//example.com/page"
        # After cleaning: {"url": "https:, "count": 1}  -- which is invalid JSON
        # This is a known limitation: malformed JSON + URLs = potential breakage
        # The result depends on whether the cleaned version happens to parse
        # The important thing is it doesn't crash
        assert result is None or isinstance(result, (dict, list))

    def test_valid_json_with_double_slash_in_string_parses_directly(self):
        """Valid JSON with // in string values parses on the direct parse step
        and never hits artifact cleaning, so URLs are preserved."""
        text = '{"url": "https://example.com/path", "title": "Test"}'
        result = extract_json(text)
        assert result == {"url": "https://example.com/path", "title": "Test"}


class TestContentAttributeFormats:
    """Tests for different LangChain content attribute formats."""

    def test_content_attribute_is_list_of_content_blocks(self):
        """LangChain multimodal AIMessage can have content as a list of blocks.
        get_llm_response_text extracts the text from the text blocks (joining
        them, dropping non-text blocks like image_url) — not the list repr."""

        class FakeMessage:
            content = [
                {"type": "text", "text": '{"key": "value"}'},
                {"type": "image_url", "image_url": "data:..."},
            ]

        text = get_llm_response_text(FakeMessage())
        # The text block is extracted cleanly; the image_url block is dropped.
        assert text == '{"key": "value"}'
        # Not the list's Python repr, and no non-text block content leaks.
        assert "image_url" not in text
        assert "data:" not in text


class TestBracketMismatchEdgeCases:
    """Tests for bracket extraction edge cases with multiple JSON objects."""

    def test_bracket_mismatch_across_separate_json_objects(self):
        """Text like '{"a": 1} middle {"b": 2}' - rfind grabs the last },
        so extraction spans from first { to last }, giving
        '{"a": 1} middle {"b": 2}' which isn't valid JSON."""
        text = 'Here is {"a": 1} and also {"b": 2} done'
        result = extract_json(text)
        # The bracket extraction grabs from first { to last }:
        # '{"a": 1} and also {"b": 2}'
        # This isn't valid JSON, so it fails. Artifact cleaning won't help.
        # Result should be None since the combined span isn't valid JSON.
        assert result is None

    def test_single_json_object_in_prose_succeeds(self):
        """Single JSON object in prose works because find/rfind grab
        matching brackets correctly."""
        text = 'The result is {"status": "ok", "count": 42} as expected.'
        result = extract_json(text)
        assert result == {"status": "ok", "count": 42}
