"""Tests for the autodebug_probe recorder module."""

import json
import tempfile
from datetime import date, datetime
from pathlib import Path

import pytest


class TestJsonDefault:
    """Tests for JSON serialization with custom default handler."""

    def test_datetime_serialization(self):
        """Test datetime objects are serialized to ISO format."""
        from autodebug_probe.recorder import _json_default

        dt = datetime(2025, 1, 15, 10, 30, 45)
        result = _json_default(dt)
        assert result == "2025-01-15T10:30:45"

    def test_date_serialization(self):
        """Test date objects are serialized to ISO format."""
        from autodebug_probe.recorder import _json_default

        d = date(2025, 1, 15)
        result = _json_default(d)
        assert result == "2025-01-15"

    def test_bytes_utf8_serialization(self):
        """Test UTF-8 bytes are decoded to string."""
        from autodebug_probe.recorder import _json_default

        b = b"hello world"
        result = _json_default(b)
        assert result == "hello world"

    def test_bytes_binary_serialization(self):
        """Test non-UTF-8 bytes are base64 encoded."""
        from autodebug_probe.recorder import _json_default

        b = b"\x80\x81\x82"  # Invalid UTF-8
        result = _json_default(b)
        assert isinstance(result, dict)
        assert "__bytes__" in result

    def test_unsupported_type_raises(self):
        """Test unsupported types raise TypeError."""
        from autodebug_probe.recorder import _json_default

        class CustomClass:
            pass

        with pytest.raises(TypeError):
            _json_default(CustomClass())


class TestStreamWriter:
    """Tests for StreamWriter class."""

    def test_write_jsonl(self):
        """Test writing JSONL records."""
        import zstandard as zstd

        from autodebug_probe.recorder import StreamWriter

        with tempfile.TemporaryDirectory() as tmpdir:
            path = Path(tmpdir) / "test.jsonl.zst"
            writer = StreamWriter(path, zstd.ZstdCompressor(level=3))

            writer.write_jsonl({"key": "value1"})
            writer.write_jsonl({"key": "value2"})
            writer.close()

            # Read back and verify
            with open(path, "rb") as f:
                reader = zstd.ZstdDecompressor().stream_reader(f)
                content = reader.read().decode("utf-8")

            lines = content.strip().split("\n")
            assert len(lines) == 2
            assert json.loads(lines[0]) == {"key": "value1"}
            assert json.loads(lines[1]) == {"key": "value2"}

    def test_write_with_datetime(self):
        """Test writing records containing datetime objects."""
        import zstandard as zstd

        from autodebug_probe.recorder import StreamWriter

        with tempfile.TemporaryDirectory() as tmpdir:
            path = Path(tmpdir) / "test.jsonl.zst"
            writer = StreamWriter(path, zstd.ZstdCompressor(level=3))

            record = {
                "timestamp": datetime(2025, 1, 15, 10, 30, 45),
                "date": date(2025, 1, 15),
            }
            writer.write_jsonl(record)
            writer.close()

            # Read back and verify
            with open(path, "rb") as f:
                reader = zstd.ZstdDecompressor().stream_reader(f)
                content = reader.read().decode("utf-8")

            data = json.loads(content.strip())
            assert data["timestamp"] == "2025-01-15T10:30:45"
            assert data["date"] == "2025-01-15"


class TestRecorder:
    """Tests for Recorder class."""

    def test_recorder_creates_files(self):
        """Test recorder creates all expected stream files."""
        from autodebug_probe.recorder import Recorder

        with tempfile.TemporaryDirectory() as tmpdir:
            run_dir = Path(tmpdir)
            recorder = Recorder(run_dir)

            # Record some events
            recorder.record_event({"type": "TEST", "data": "event"})
            recorder.record_http({"url": "http://example.com", "status": 200})
            recorder.record_sql({"query": "SELECT 1", "result": []})
            recorder.record_time_rng({"type": "TIME", "value": 123.456})

            recorder.close()

            # Check files exist
            assert (run_dir / "events.jsonl.zst").exists()
            assert (run_dir / "deps_http.jsonl.zst").exists()
            assert (run_dir / "deps_sql.jsonl.zst").exists()
            assert (run_dir / "time_rng.jsonl.zst").exists()

    def test_recorder_sequence_numbers(self):
        """Test recorder assigns sequential sequence numbers."""
        import zstandard as zstd

        from autodebug_probe.recorder import Recorder

        with tempfile.TemporaryDirectory() as tmpdir:
            run_dir = Path(tmpdir)
            recorder = Recorder(run_dir)

            recorder.record_event({"type": "TEST1"})
            recorder.record_event({"type": "TEST2"})
            recorder.record_event({"type": "TEST3"})

            recorder.close()

            # Read back events
            with open(run_dir / "events.jsonl.zst", "rb") as f:
                reader = zstd.ZstdDecompressor().stream_reader(f)
                content = reader.read().decode("utf-8")

            lines = content.strip().split("\n")
            records = [json.loads(line) for line in lines]

            assert records[0]["seq"] == 1
            assert records[1]["seq"] == 2
            assert records[2]["seq"] == 3

    def test_recorder_closed_ignores_writes(self):
        """Test recorder ignores writes after close."""
        import zstandard as zstd

        from autodebug_probe.recorder import Recorder

        with tempfile.TemporaryDirectory() as tmpdir:
            run_dir = Path(tmpdir)
            recorder = Recorder(run_dir)

            recorder.record_event({"type": "BEFORE"})
            recorder.close()
            recorder.record_event({"type": "AFTER"})  # Should be ignored

            # Read back events
            with open(run_dir / "events.jsonl.zst", "rb") as f:
                reader = zstd.ZstdDecompressor().stream_reader(f)
                content = reader.read().decode("utf-8")

            lines = content.strip().split("\n")
            assert len(lines) == 1
            assert json.loads(lines[0])["type"] == "BEFORE"
