"""
Tests for LLM parser Core module.

Tests parsing functions for Claude and OpenCode CLI outputs.
"""

import pytest

from lattice.core.llm_parser import (
    extract_claude_text,
    extract_opencode_text,
    extract_text_from_jsonl,
)


class TestExtractClaudeText:
    """Tests for extract_claude_text function."""

    def test_content_with_text_blocks(self):
        """Should extract text from content blocks."""
        data = {
            "content": [
                {"type": "text", "text": "Hello"},
                {"type": "text", "text": " world"},
            ]
        }
        assert extract_claude_text(data) == "Hello world"

    def test_content_with_single_text_block(self):
        """Should extract text from single content block."""
        data = {"content": [{"type": "text", "text": "Hello"}]}
        assert extract_claude_text(data) == "Hello"

    def test_content_with_mixed_blocks(self):
        """Should only extract text blocks, ignoring other types."""
        data = {
            "content": [
                {"type": "text", "text": "Hello"},
                {"type": "image", "source": {"data": "..."}},
                {"type": "text", "text": " world"},
            ]
        }
        assert extract_claude_text(data) == "Hello world"

    def test_content_with_empty_blocks(self):
        """Should return None when no text blocks found."""
        data = {"content": [{"type": "image", "source": {"data": "..."}}]}
        assert extract_claude_text(data) is None

    def test_content_with_empty_list(self):
        """Should return None for empty content list."""
        data = {"content": []}
        assert extract_claude_text(data) is None

    def test_content_as_string(self):
        """Should return string content directly."""
        data = {"content": "Direct string"}
        assert extract_claude_text(data) == "Direct string"

    def test_result_field_fallback(self):
        """Should use result field when content not found."""
        data = {"result": "Fallback result"}
        assert extract_claude_text(data) == "Fallback result"

    def test_content_takes_priority_over_result(self):
        """Should prefer content over result field."""
        data = {"content": "From content", "result": "From result"}
        assert extract_claude_text(data) == "From content"

    def test_unrecognized_format(self):
        """Should return None for unrecognized format."""
        data = {"other": "data"}
        assert extract_claude_text(data) is None

    def test_empty_dict(self):
        """Should return None for empty dict."""
        assert extract_claude_text({}) is None

    def test_content_with_missing_text_key(self):
        """Should handle blocks without text key."""
        data = {"content": [{"type": "text"}]}
        assert extract_claude_text(data) == ""


class TestExtractOpencodeText:
    """Tests for extract_opencode_text function."""

    def test_text_type_with_part(self):
        """Should extract text from type=text with part."""
        data = {"type": "text", "part": {"text": "Hello"}}
        assert extract_opencode_text(data) == "Hello"

    def test_text_type_without_part(self):
        """Should return None when text type has no part."""
        data = {"type": "text"}
        assert extract_opencode_text(data) is None

    def test_text_type_with_empty_part(self):
        """Should return None when part has no text."""
        data = {"type": "text", "part": {}}
        assert extract_opencode_text(data) is None

    def test_content_field(self):
        """Should use content field."""
        data = {"content": "Direct content"}
        assert extract_opencode_text(data) == "Direct content"

    def test_response_field(self):
        """Should use response field."""
        data = {"response": "Response text"}
        assert extract_opencode_text(data) == "Response text"

    def test_text_type_takes_priority(self):
        """Should prefer text type over content/response."""
        data = {"type": "text", "part": {"text": "Primary"}, "content": "Secondary"}
        assert extract_opencode_text(data) == "Primary"

    def test_content_over_response(self):
        """Should prefer content over response."""
        data = {"content": "From content", "response": "From response"}
        assert extract_opencode_text(data) == "From content"

    def test_empty_dict(self):
        """Should return None for empty dict."""
        assert extract_opencode_text({}) is None

    def test_unrecognized_type(self):
        """Should return None for unrecognized type."""
        data = {"type": "other"}
        assert extract_opencode_text(data) is None


class TestExtractTextFromJsonl:
    """Tests for extract_text_from_jsonl function."""

    def test_single_line_jsonl(self):
        """Should extract text from single line."""
        text = '{"type": "text", "part": {"text": "Hello"}}'
        assert extract_text_from_jsonl(text) == "Hello"

    def test_multiline_jsonl(self):
        """Should find text in multiline JSONL."""
        text = '{"other": true}\n{"type": "text", "part": {"text": "Found"}}'
        assert extract_text_from_jsonl(text) == "Found"

    def test_empty_lines_ignored(self):
        """Should ignore empty lines."""
        text = '{"other": true}\n\n{"type": "text", "part": {"text": "OK"}}'
        assert extract_text_from_jsonl(text) == "OK"

    def test_invalid_json_ignored(self):
        """Should skip invalid JSON lines."""
        text = 'not valid json\n{"type": "text", "part": {"text": "OK"}}'
        assert extract_text_from_jsonl(text) == "OK"

    def test_no_valid_text(self):
        """Should return None when no text found."""
        text = '{"other": true}\n{"more": false}'
        assert extract_text_from_jsonl(text) is None

    def test_empty_string(self):
        """Should return None for empty string."""
        assert extract_text_from_jsonl("") is None

    def test_whitespace_only(self):
        """Should return None for whitespace only."""
        assert extract_text_from_jsonl("   \n  \n  ") is None

    def test_first_match_returned(self):
        """Should return first text match."""
        text = '{"type": "text", "part": {"text": "First"}}\n{"type": "text", "part": {"text": "Second"}}'
        assert extract_text_from_jsonl(text) == "First"

    def test_non_dict_json_ignored(self):
        """Should ignore non-dict JSON values."""
        text = '["array"]\n42\n{"type": "text", "part": {"text": "OK"}}'
        assert extract_text_from_jsonl(text) == "OK"
