"""OpenAI Codex CLI rollout JSONL parser."""

import json
from datetime import datetime
from pathlib import Path
from typing import List, Optional

from .base import BaseParser
from ..models import Conversation, Message

# System prompt patterns to skip (injected by Codex, not real user messages)
_SYSTEM_PREFIXES = (
    "# AGENTS.md",
    "# agents.md",
    "<INSTRUCTIONS>",
    "## Skills\n",
)


class CodexParser(BaseParser):
    def can_parse(self, path: Path) -> bool:
        if path.is_dir():
            if path.name == ".codex" or (path / "sessions").is_dir():
                return bool(list((path if path.name == ".codex" else path).glob("sessions/**/*.jsonl")))
            return False
        if path.is_file() and path.suffix == ".jsonl":
            try:
                with open(path, encoding="utf-8") as f:
                    first = json.loads(f.readline())
                return first.get("type") in ("session_meta", "response_item", "turn_context", "event_msg")
            except (json.JSONDecodeError, IOError):
                pass
        return False

    def parse(self, path: Path) -> List[Conversation]:
        if path.is_dir():
            base = path if (path / "sessions").is_dir() else path
            convs = []
            for jsonl_file in sorted(base.glob("sessions/**/*.jsonl")):
                conv = self._parse_rollout(jsonl_file)
                if conv:
                    convs.append(conv)
            convs.sort(key=lambda c: c.created or datetime.min)
            return convs
        elif path.is_file():
            conv = self._parse_rollout(path)
            return [conv] if conv else []
        return []

    def _parse_rollout(self, path: Path) -> Optional[Conversation]:
        messages = []
        created = None

        try:
            with open(path, encoding="utf-8") as f:
                for line in f:
                    line = line.strip()
                    if not line:
                        continue
                    try:
                        obj = json.loads(line)
                    except json.JSONDecodeError:
                        continue

                    if obj.get("type") == "response_item":
                        payload = obj.get("payload", {})
                        role = payload.get("role", "")
                        if role not in ("user", "assistant"):
                            continue

                        content = self._extract_text(payload.get("content", []))
                        if not content:
                            continue

                        # Skip system-injected messages
                        if role == "user" and any(content.lstrip().startswith(p) for p in _SYSTEM_PREFIXES):
                            continue

                        ts = self._parse_ts(obj.get("timestamp"))
                        messages.append(Message(role=role, content=content, timestamp=ts))

                        if ts and created is None:
                            created = ts
        except IOError:
            return None

        if not messages:
            return None

        return Conversation(
            id=path.stem,
            title=messages[0].content[:50] if messages else "",
            messages=messages,
            created=created,
            platform="codex",
        )

    def _extract_text(self, content) -> str:
        if isinstance(content, str):
            return content
        if isinstance(content, list):
            for item in content:
                if isinstance(item, dict):
                    text = item.get("text", "")
                    if text:
                        return text
                elif isinstance(item, str):
                    return item
        return ""

    def _parse_ts(self, ts_str) -> Optional[datetime]:
        if not ts_str:
            return None
        try:
            return datetime.fromisoformat(ts_str.replace("Z", "+00:00")).replace(tzinfo=None)
        except (ValueError, TypeError):
            return None
