"""Tests for claude_code.transcript — JSONL transcript parsing."""
from __future__ import annotations

import json

import pytest

from staso.claude_code.transcript import count_lines, parse_assistant_messages


def _write_transcript(tmp_path, lines: list[dict]) -> str:
    path = tmp_path / "session.jsonl"
    path.write_text("\n".join(json.dumps(line) for line in lines), encoding="utf-8")
    return str(path)


class TestCountLines:
    def test_counts_all_lines(self, tmp_path):
        # Counts raw lines (including blank) to stay consistent with
        # parse_assistant_messages which uses raw 1-indexed positions.
        path = tmp_path / "t.jsonl"
        path.write_text('{"a":1}\n\n{"b":2}\n', encoding="utf-8")
        assert count_lines(str(path)) == 3

    def test_missing_file_returns_zero(self, tmp_path):
        assert count_lines(str(tmp_path / "nope.jsonl")) == 0


class TestParseAssistantMessages:
    def test_empty_transcript(self, tmp_path):
        path = _write_transcript(tmp_path, [])
        msgs, last = parse_assistant_messages(str(path), 0)
        assert msgs == []
        assert last == 0

    def test_parses_assistant_message(self, tmp_path):
        lines = [
            {"type": "user", "role": "user", "content": "hi", "timestamp": "2026-01-01T00:00:00Z"},
            {
                "type": "assistant",
                "message": {
                    "id": "msg_abc",
                    "model": "claude-sonnet-4-6",
                    "content": [{"type": "text", "text": "hello"}],
                    "usage": {
                        "input_tokens": 10,
                        "output_tokens": 5,
                        "cache_read_input_tokens": 3,
                        "cache_creation_input_tokens": 1,
                    },
                },
                "timestamp": "2026-01-01T00:00:01Z",
            },
        ]
        path = _write_transcript(tmp_path, lines)
        msgs, last = parse_assistant_messages(str(path), 0)

        assert len(msgs) == 1
        m = msgs[0]
        assert m.message_id == "msg_abc"
        assert m.model == "claude-sonnet-4-6"
        assert m.input_tokens == 10
        assert m.output_tokens == 5
        assert m.total_tokens == 15
        assert m.cache_read_tokens == 3
        assert m.cache_creation_tokens == 1
        assert m.timestamp == "2026-01-01T00:00:01Z"
        assert last == 2

    def test_skips_lines_before_start_line(self, tmp_path):
        lines = [
            {"type": "assistant", "message": {"id": "old", "model": "m", "content": [], "usage": {"input_tokens": 1, "output_tokens": 1}}, "timestamp": ""},
            {"type": "assistant", "message": {"id": "new", "model": "m", "content": [], "usage": {"input_tokens": 2, "output_tokens": 2}}, "timestamp": ""},
        ]
        path = _write_transcript(tmp_path, lines)
        # Start after the first line
        msgs, last = parse_assistant_messages(str(path), 1)
        assert len(msgs) == 1
        assert msgs[0].message_id == "new"
        assert last == 2

    def test_skips_non_assistant_entries(self, tmp_path):
        lines = [
            {"type": "user", "role": "user", "content": "question"},
            {"type": "assistant", "message": {"id": "r", "model": "m", "content": [], "usage": {}}},
            {"type": "user", "role": "user", "content": [{"type": "tool_result", "content": "output"}]},
        ]
        path = _write_transcript(tmp_path, lines)
        msgs, _ = parse_assistant_messages(str(path), 0)
        assert len(msgs) == 1

    def test_missing_file_returns_empty(self, tmp_path):
        msgs, last = parse_assistant_messages(str(tmp_path / "no.jsonl"), 0)
        assert msgs == []
        assert last == 0

    def test_multiple_assistant_messages(self, tmp_path):
        def _assistant(idx: int) -> dict:
            return {
                "type": "assistant",
                "message": {
                    "id": f"msg_{idx}",
                    "model": "claude-sonnet-4-6",
                    "content": [],
                    "usage": {"input_tokens": idx * 10, "output_tokens": idx * 5},
                },
                "timestamp": f"2026-01-01T00:00:0{idx}Z",
            }

        path = _write_transcript(tmp_path, [_assistant(1), _assistant(2), _assistant(3)])
        msgs, _ = parse_assistant_messages(str(path), 0)
        assert len(msgs) == 3
        assert [m.message_id for m in msgs] == ["msg_1", "msg_2", "msg_3"]

    def test_handles_malformed_json_lines(self, tmp_path):
        path = tmp_path / "session.jsonl"
        path.write_text(
            '{"type":"user","content":"hi"}\nnot-json\n{"type":"assistant","message":{"id":"r","model":"m","content":[],"usage":{}}}\n',
            encoding="utf-8",
        )
        msgs, _ = parse_assistant_messages(str(path), 0)
        assert len(msgs) == 1
