"""
ShelfAI transcript parser.

Parses conversation transcripts from multiple formats into a unified
Transcript structure for processing by the session management agent.
"""

import json
import re
from dataclasses import dataclass, field
from typing import Optional


@dataclass
class Message:
    """A single message in a conversation."""

    role: str  # "user", "assistant", "system", "tool"
    content: str
    timestamp: Optional[str] = None
    tool_calls: list = field(default_factory=list)
    tool_results: list = field(default_factory=list)


@dataclass
class Transcript:
    """A parsed conversation transcript."""

    messages: list  # List[Message]
    metadata: dict = field(default_factory=dict)
    source_format: str = "unknown"

    @property
    def user_messages(self) -> list:
        """All messages from the user."""
        return [m for m in self.messages if m.role == "user"]

    @property
    def assistant_messages(self) -> list:
        """All messages from the assistant."""
        return [m for m in self.messages if m.role == "assistant"]

    @property
    def message_count(self) -> int:
        """Total number of messages."""
        return len(self.messages)

    @property
    def text(self) -> str:
        """Full transcript as readable text for LLM consumption."""
        lines = []
        for m in self.messages:
            lines.append(f"## {m.role.title()}\n{m.content}\n")
        return "\n".join(lines)


class TranscriptParser:
    """
    Parses conversation transcripts from multiple formats.

    Supported formats:
        - JSON: {"messages": [{"role": "user", "content": "..."}]}
        - Markdown: ## User / ## Assistant headers
        - Simple: "User: ..." / "Assistant: ..." lines
        - Raw: Treated as a single user message

    Usage:
        parser = TranscriptParser()
        transcript = parser.parse(text)
        transcript = parser.parse_file("conversation.md")
    """

    # Role name normalization map
    ROLE_MAP = {
        "human": "user",
        "ai": "assistant",
        "bot": "assistant",
        "claude": "assistant",
        "gpt": "assistant",
        "chatgpt": "assistant",
    }

    def parse(self, content: str) -> Transcript:
        """
        Auto-detect format and parse a transcript string.

        Args:
            content: Raw transcript text

        Returns:
            Parsed Transcript object
        """
        content = content.strip()
        if not content:
            return Transcript(messages=[], source_format="empty")

        # Try JSON first
        if content.startswith("{") or content.startswith("["):
            try:
                return self._parse_json(content)
            except (json.JSONDecodeError, ValueError):
                pass  # Fall through to other formats

        # Try markdown with role headers
        if re.search(
            r"^##\s+(User|Assistant|System|Human|AI|Claude)\b",
            content,
            re.MULTILINE | re.IGNORECASE,
        ):
            return self._parse_markdown(content)

        # Try simple alternating format
        if re.search(
            r"^(User|Assistant|Human|AI|Claude|System)\s*:",
            content,
            re.MULTILINE | re.IGNORECASE,
        ):
            return self._parse_simple(content)

        # Fallback: treat as raw content
        return Transcript(
            messages=[Message(role="user", content=content)],
            source_format="raw",
        )

    def parse_file(self, path: str) -> Transcript:
        """
        Parse a transcript from a file.

        Args:
            path: Path to the transcript file

        Returns:
            Parsed Transcript object
        """
        with open(path, "r", encoding="utf-8") as f:
            content = f.read()
        return self.parse(content)

    def _normalize_role(self, role: str) -> str:
        """Normalize role names to standard values."""
        role = role.strip().lower()
        return self.ROLE_MAP.get(role, role)

    def _parse_json(self, content: str) -> Transcript:
        """Parse JSON message format."""
        data = json.loads(content)

        if isinstance(data, list):
            messages_data = data
            metadata = {}
        elif isinstance(data, dict):
            messages_data = data.get("messages", [])
            metadata = data.get("metadata", {})
        else:
            raise ValueError("JSON must be an array or an object with 'messages' key")

        messages = []
        for m in messages_data:
            messages.append(
                Message(
                    role=self._normalize_role(m.get("role", "user")),
                    content=m.get("content", ""),
                    timestamp=m.get("timestamp"),
                    tool_calls=m.get("tool_calls", []),
                    tool_results=m.get("tool_results", []),
                )
            )

        return Transcript(messages=messages, metadata=metadata, source_format="json")

    def _parse_markdown(self, content: str) -> Transcript:
        """Parse markdown with ## Role headers."""
        messages = []
        pattern = r"^##\s+(User|Assistant|System|Human|AI|Claude)\b\s*$"
        parts = re.split(pattern, content, flags=re.MULTILINE | re.IGNORECASE)

        # parts alternates: [pre-header text, role1, content1, role2, content2, ...]
        i = 1
        while i < len(parts) - 1:
            role = self._normalize_role(parts[i])
            body = parts[i + 1].strip()
            if body:  # Skip empty messages
                messages.append(Message(role=role, content=body))
            i += 2

        return Transcript(messages=messages, source_format="markdown")

    def _parse_simple(self, content: str) -> Transcript:
        """Parse 'Role: content' format."""
        messages = []
        pattern = r"^(User|Assistant|Human|AI|Claude|System)\s*:\s*"
        parts = re.split(pattern, content, flags=re.MULTILINE | re.IGNORECASE)

        i = 1
        while i < len(parts) - 1:
            role = self._normalize_role(parts[i])
            body = parts[i + 1].strip()
            if body:
                messages.append(Message(role=role, content=body))
            i += 2

        return Transcript(messages=messages, source_format="simple")
