"""Tests for transcript loading and replay index.

Tests TranscriptIndex type isolation, exhaustion behavior, and
JSONL loading edge cases.
"""

from __future__ import annotations

import json

import pytest

from autodebug_replay.transcripts import (
    ReplayDivergence,
    TranscriptIndex,
    _read_jsonl_file,
    load_transcripts,
)

# --- TranscriptIndex ---


class TestTranscriptIndexTypeIsolation:
    """Each record type has its own independent position counter."""

    def test_accessing_http_does_not_advance_sql(self):
        """Getting HTTP records should not affect SQL position."""
        records = [
            {"type": "HTTP", "method": "GET", "url": "/api/test"},
            {"type": "SQL", "query": "SELECT 1"},
            {"type": "HTTP", "method": "POST", "url": "/api/create"},
        ]
        idx = TranscriptIndex(records=records)

        # Get first HTTP
        http1 = idx.expect("HTTP")
        assert http1["method"] == "GET"

        # SQL should still be at position 0
        sql1 = idx.expect("SQL")
        assert sql1["query"] == "SELECT 1"

        # Second HTTP should work
        http2 = idx.expect("HTTP")
        assert http2["method"] == "POST"

    def test_accessing_different_types_independently(self):
        """Multiple types can be consumed independently in any order."""
        records = [
            {"type": "HTTP", "data": "h1"},
            {"type": "SQL", "data": "s1"},
            {"type": "REDIS", "data": "r1"},
            {"type": "HTTP", "data": "h2"},
            {"type": "SQL", "data": "s2"},
        ]
        idx = TranscriptIndex(records=records)

        # Access in non-sequential type order
        assert idx.expect("SQL")["data"] == "s1"
        assert idx.expect("HTTP")["data"] == "h1"
        assert idx.expect("REDIS")["data"] == "r1"
        assert idx.expect("HTTP")["data"] == "h2"
        assert idx.expect("SQL")["data"] == "s2"


class TestTranscriptIndexExhaustion:
    """Accessing past the end of a type's records should raise ReplayDivergence."""

    def test_exhaustion_raises_divergence(self):
        """Requesting more records than available should raise."""
        records = [{"type": "HTTP", "method": "GET", "url": "/test"}]
        idx = TranscriptIndex(records=records)

        idx.expect("HTTP")  # Consume the only HTTP record
        with pytest.raises(ReplayDivergence):
            idx.expect("HTTP")  # No more HTTP records

    def test_nonexistent_type_raises_divergence(self):
        """Requesting a type with zero records should raise."""
        records = [{"type": "HTTP", "method": "GET", "url": "/test"}]
        idx = TranscriptIndex(records=records)

        with pytest.raises(ReplayDivergence):
            idx.expect("SQL")  # No SQL records exist

    def test_empty_transcript_raises_divergence(self):
        """Empty transcript should raise for any type."""
        idx = TranscriptIndex(records=[])

        with pytest.raises(ReplayDivergence):
            idx.expect("HTTP")


class TestTranscriptIndexHasMore:
    """Tests for has_more() correctness."""

    def test_has_more_true_when_records_exist(self):
        """has_more should return True when unconsumed records exist."""
        records = [
            {"type": "HTTP", "method": "GET"},
            {"type": "HTTP", "method": "POST"},
        ]
        idx = TranscriptIndex(records=records)
        assert idx.has_more("HTTP") is True

    def test_has_more_false_when_exhausted(self):
        """has_more should return False when all records consumed."""
        records = [{"type": "HTTP", "method": "GET"}]
        idx = TranscriptIndex(records=records)
        idx.expect("HTTP")
        assert idx.has_more("HTTP") is False

    def test_has_more_false_for_nonexistent_type(self):
        """has_more should return False for types with no records."""
        records = [{"type": "HTTP", "method": "GET"}]
        idx = TranscriptIndex(records=records)
        assert idx.has_more("SQL") is False


class TestReplayDivergenceFormat:
    """Tests for ReplayDivergence exception formatting."""

    def test_divergence_contains_code(self):
        """ReplayDivergence should include the error code in its message."""
        with pytest.raises(ReplayDivergence) as exc_info:
            raise ReplayDivergence("MISSING_DEP", {"type": "HTTP"})
        assert "MISSING_DEP" in str(exc_info.value)

    def test_divergence_is_runtime_error(self):
        """ReplayDivergence should be a RuntimeError subclass."""
        assert issubclass(ReplayDivergence, RuntimeError)


class TestJsonlReading:
    """Tests for JSONL file reading."""

    def test_reads_valid_jsonl(self, tmp_path):
        """Should read valid JSONL file correctly."""
        f = tmp_path / "test.jsonl"
        records = [{"type": "HTTP", "n": i} for i in range(5)]
        f.write_text("\n".join(json.dumps(r) for r in records))

        result = _read_jsonl_file(f)
        assert len(result) == 5
        assert result[0]["n"] == 0
        assert result[4]["n"] == 4

    def test_handles_empty_file(self, tmp_path):
        """Should handle empty JSONL file gracefully."""
        f = tmp_path / "empty.jsonl"
        f.write_text("")

        result = _read_jsonl_file(f)
        assert result == []

    def test_handles_blank_lines(self, tmp_path):
        """Should skip blank lines in JSONL."""
        f = tmp_path / "gaps.jsonl"
        f.write_text('{"type": "HTTP"}\n\n{"type": "SQL"}\n')

        result = _read_jsonl_file(f)
        assert len(result) == 2


class TestLoadTranscripts:
    """Tests for load_transcripts() directory loading."""

    def test_loads_from_directory(self, tmp_path):
        """Should load transcripts from known filenames in directory."""
        # Write a deps_http.jsonl file
        http_file = tmp_path / "deps_http.jsonl"
        http_file.write_text(json.dumps({"type": "HTTP", "method": "GET", "url": "/test"}))

        # Write a deps_sql.jsonl file
        sql_file = tmp_path / "deps_sql.jsonl"
        sql_file.write_text(json.dumps({"type": "SQL", "query": "SELECT 1"}))

        idx = load_transcripts(tmp_path)
        assert idx.has_more("HTTP")
        assert idx.has_more("SQL")

    def test_handles_missing_files(self, tmp_path):
        """Should handle missing transcript files gracefully."""
        # Empty directory - no transcript files
        idx = load_transcripts(tmp_path)
        assert idx.has_more("HTTP") is False
