"""Type definitions for Claude Code JSONL message format."""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any


@dataclass
class ThinkingBlock:
    type: str  # "thinking"
    thinking: str
    signature: str | None = None


@dataclass
class TextBlock:
    type: str  # "text"
    text: str


@dataclass
class ToolUseBlock:
    type: str  # "tool_use"
    id: str
    name: str
    input: dict[str, Any] = field(default_factory=dict)


ContentBlock = ThinkingBlock | TextBlock | ToolUseBlock


def parse_content_block(data: dict[str, Any]) -> ContentBlock:
    block_type = data.get("type", "")
    if block_type == "thinking":
        return ThinkingBlock(
            type="thinking",
            thinking=data.get("thinking", ""),
            signature=data.get("signature"),
        )
    elif block_type == "text":
        return TextBlock(type="text", text=data.get("text", ""))
    elif block_type == "tool_use":
        return ToolUseBlock(
            type="tool_use",
            id=data.get("id", ""),
            name=data.get("name", ""),
            input=data.get("input", {}),
        )
    else:
        return TextBlock(type="text", text=str(data))


@dataclass
class CCUsage:
    input_tokens: int = 0
    output_tokens: int = 0
    cache_creation_input_tokens: int = 0
    cache_read_input_tokens: int = 0
    service_tier: str | None = None

    @classmethod
    def from_dict(cls, data: dict[str, Any] | None) -> CCUsage:
        if not data:
            return cls()
        return cls(
            input_tokens=data.get("input_tokens", 0) or 0,
            output_tokens=data.get("output_tokens", 0) or 0,
            cache_creation_input_tokens=data.get("cache_creation_input_tokens", 0) or 0,
            cache_read_input_tokens=data.get("cache_read_input_tokens", 0) or 0,
            service_tier=data.get("service_tier"),
        )


@dataclass
class CCMessage:
    """Base for all CC JSONL messages. Fields vary by type."""

    type: str  # "user", "assistant", "system", "progress", "file-history-snapshot", "queue-operation"
    uuid: str | None = None
    parent_uuid: str | None = None
    timestamp: str | None = None
    session_id: str | None = None
    is_sidechain: bool = False
    version: str | None = None
    cwd: str | None = None
    git_branch: str | None = None
    raw: dict[str, Any] = field(default_factory=dict)

    # user message fields
    user_type: str | None = None  # "external"
    is_compact_summary: bool = False
    source_tool_assistant_uuid: str | None = None
    tool_use_result: Any = None

    # assistant message fields
    model: str | None = None
    message_id: str | None = None  # message.id from Anthropic API
    request_id: str | None = None
    content_blocks: list[ContentBlock] = field(default_factory=list)
    usage: CCUsage = field(default_factory=CCUsage)
    stop_reason: str | None = None

    # message content (string for user, varies for others)
    content: Any = None  # str or list[dict]

    # system message fields
    subtype: str | None = None  # "compact_boundary", "api_error", etc.
    level: str | None = None
    compact_metadata: dict[str, Any] | None = None
    microcompact_metadata: dict[str, Any] | None = None
    error: dict[str, Any] | None = None


def parse_message(data: dict[str, Any]) -> CCMessage:
    """Parse a raw JSONL dict into a CCMessage."""
    msg_type = data.get("type", "")

    msg = CCMessage(
        type=msg_type,
        uuid=data.get("uuid"),
        parent_uuid=data.get("parentUuid"),
        timestamp=data.get("timestamp"),
        session_id=data.get("sessionId"),
        is_sidechain=data.get("isSidechain", False),
        version=data.get("version"),
        cwd=data.get("cwd"),
        git_branch=data.get("gitBranch"),
        raw=data,
    )

    if msg_type == "user":
        msg.user_type = data.get("userType")
        msg.is_compact_summary = data.get("isCompactSummary", False)
        msg.source_tool_assistant_uuid = data.get("sourceToolAssistantUUID")
        msg.tool_use_result = data.get("toolUseResult")
        message = data.get("message", {})
        msg.content = message.get("content") if isinstance(message, dict) else None

    elif msg_type == "assistant":
        message = data.get("message", {})
        if isinstance(message, dict):
            msg.model = message.get("model")
            msg.message_id = message.get("id")
            msg.stop_reason = message.get("stop_reason")
            msg.usage = CCUsage.from_dict(message.get("usage"))
            raw_content = message.get("content", [])
            if isinstance(raw_content, list):
                msg.content_blocks = [parse_content_block(b) for b in raw_content]
        msg.request_id = data.get("requestId")

    elif msg_type == "system":
        msg.subtype = data.get("subtype")
        msg.level = data.get("level")
        msg.content = data.get("content")
        msg.compact_metadata = data.get("compactMetadata")
        msg.microcompact_metadata = data.get("microcompactMetadata")
        msg.error = data.get("error")

    return msg
