"""Tests for LoadTracesStep — generic JSONL file loader."""

from __future__ import annotations

import json
from pathlib import Path

import pytest

from ace.core.context import ACEStepContext
from ace.steps.load_traces import LoadTracesStep


@pytest.fixture
def load_step():
    return LoadTracesStep()


@pytest.fixture
def sample_jsonl(tmp_path: Path) -> Path:
    """Create a sample JSONL file with valid events."""
    path = tmp_path / "session.jsonl"
    events = [
        {"type": "session", "id": "s1", "timestamp": "2026-01-01T00:00:00Z"},
        {
            "type": "message",
            "id": "m1",
            "timestamp": "2026-01-01T00:00:01Z",
            "message": {"role": "user", "content": [{"type": "text", "text": "hello"}]},
        },
        {
            "type": "message",
            "id": "m2",
            "timestamp": "2026-01-01T00:00:02Z",
            "message": {
                "role": "assistant",
                "content": [{"type": "text", "text": "hi there"}],
            },
        },
    ]
    path.write_text("\n".join(json.dumps(e) for e in events) + "\n")
    return path


class TestLoadTracesStep:
    def test_requires_provides(self, load_step: LoadTracesStep):
        assert load_step.requires == frozenset({"sample"})
        assert load_step.provides == frozenset({"trace"})

    def test_valid_jsonl(self, load_step: LoadTracesStep, sample_jsonl: Path):
        ctx = ACEStepContext(sample=str(sample_jsonl))
        result = load_step(ctx)

        assert isinstance(result.trace, list)
        assert len(result.trace) == 3
        assert result.trace[0]["type"] == "session"
        assert result.trace[1]["type"] == "message"
        assert result.trace[2]["type"] == "message"

    def test_empty_file(self, load_step: LoadTracesStep, tmp_path: Path):
        path = tmp_path / "empty.jsonl"
        path.write_text("")

        ctx = ACEStepContext(sample=str(path))
        result = load_step(ctx)

        assert result.trace == []

    def test_missing_file(self, load_step: LoadTracesStep, tmp_path: Path):
        path = tmp_path / "nonexistent.jsonl"

        ctx = ACEStepContext(sample=str(path))
        result = load_step(ctx)

        assert result.trace == []

    def test_skips_unparseable_lines(self, load_step: LoadTracesStep, tmp_path: Path):
        path = tmp_path / "mixed.jsonl"
        path.write_text(
            '{"type": "session", "id": "s1"}\n'
            "this is not json\n"
            '{"type": "message", "id": "m1"}\n'
            "\n"  # blank line
            "also not json\n"
        )

        ctx = ACEStepContext(sample=str(path))
        result = load_step(ctx)

        assert len(result.trace) == 2
        assert result.trace[0]["type"] == "session"
        assert result.trace[1]["type"] == "message"

    def test_preserves_full_event_data(self, load_step: LoadTracesStep, tmp_path: Path):
        """Verify no truncation of event fields."""
        long_text = "x" * 10000
        event = {
            "type": "message",
            "id": "m1",
            "timestamp": "2026-01-01T00:00:00Z",
            "message": {
                "role": "assistant",
                "content": [
                    {"type": "thinking", "thinking": long_text},
                    {
                        "type": "toolCall",
                        "id": "tc1",
                        "name": "Read",
                        "arguments": {"file_path": "/a/b/c", "data": long_text},
                    },
                ],
            },
        }
        path = tmp_path / "full.jsonl"
        path.write_text(json.dumps(event) + "\n")

        ctx = ACEStepContext(sample=str(path))
        result = load_step(ctx)

        assert len(result.trace) == 1
        msg = result.trace[0]["message"]
        assert msg["content"][0]["thinking"] == long_text
        assert msg["content"][1]["arguments"]["data"] == long_text

    def test_returns_new_context(self, load_step: LoadTracesStep, sample_jsonl: Path):
        """Step should return a new context, not mutate the original."""
        ctx = ACEStepContext(sample=str(sample_jsonl))
        result = load_step(ctx)

        assert result is not ctx
        assert ctx.trace is None  # original unchanged
        assert result.trace is not None

    def test_with_real_sample_fixture(self, load_step: LoadTracesStep):
        """Test with the actual sample JSONL from the examples directory."""
        sample = Path(__file__).resolve().parents[1] / "examples" / "openclaw"
        jsonl_files = list(sample.glob("*.jsonl"))
        if not jsonl_files:
            pytest.skip("No sample JSONL files in examples/openclaw/")

        ctx = ACEStepContext(sample=str(jsonl_files[0]))
        result = load_step(ctx)

        assert isinstance(result.trace, list)
        assert len(result.trace) > 0
        # Should contain message events (sample file may have corrupted first line)
        types = {e.get("type") for e in result.trace}
        assert "message" in types
