from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any, Mapping


def _safe_int(value: Any) -> int | None:
    if value is None:
        return None
    try:
        return int(value)
    except (TypeError, ValueError):
        return None


def _safe_bool_or_none(value: Any) -> bool | None:
    if value is None:
        return None
    return bool(value)


def _extract_text(content: Any) -> str:
    if isinstance(content, str):
        return content

    if isinstance(content, list):
        chunks: list[str] = []
        for block in content:
            if isinstance(block, Mapping):
                text = block.get("text")
                if isinstance(text, str) and text:
                    chunks.append(text)
            elif isinstance(block, str) and block:
                chunks.append(block)
        return "\n".join(chunks)

    return ""


@dataclass(frozen=True)
class Usage:
    input_tokens: int | None = None
    output_tokens: int | None = None


@dataclass(frozen=True)
class TSEMessageResponse:
    text: str
    session_id: str | None = None
    response_type: str | None = None
    waiting_for_clarification: bool | None = None
    next_steps: list[dict[str, Any]] = field(default_factory=list)
    usage: Usage | None = None
    raw: dict[str, Any] = field(default_factory=dict)


@dataclass(frozen=True)
class ModelInfo:
    id: str
    object: str | None = None
    created: int | None = None
    owned_by: str | None = None
    raw: dict[str, Any] = field(default_factory=dict)


@dataclass(frozen=True)
class SessionInfo:
    session_id: str
    ttl_seconds: int | None = None
    created_at: str | None = None
    raw: dict[str, Any] = field(default_factory=dict)


@dataclass(frozen=True)
class SessionDeleteResult:
    session_id: str
    cleared: bool
    cleared_at: str | None = None
    raw: dict[str, Any] = field(default_factory=dict)


@dataclass(frozen=True)
class IngestResponse:
    status: str
    raw: dict[str, Any] = field(default_factory=dict)


def message_from_payload(payload: Mapping[str, Any]) -> TSEMessageResponse:
    raw = dict(payload)
    text = _extract_text(raw.get("content"))
    if not text:
        fallback = raw.get("response")
        text = str(fallback) if fallback is not None else ""

    usage: Usage | None = None
    usage_payload = raw.get("usage")
    if isinstance(usage_payload, Mapping):
        usage = Usage(
            input_tokens=_safe_int(usage_payload.get("input_tokens")),
            output_tokens=_safe_int(usage_payload.get("output_tokens")),
        )

    next_steps_payload = raw.get("next_steps")
    next_steps: list[dict[str, Any]] = []
    if isinstance(next_steps_payload, list):
        for item in next_steps_payload:
            if isinstance(item, Mapping):
                next_steps.append(dict(item))

    return TSEMessageResponse(
        text=text,
        session_id=raw.get("session_id") if isinstance(raw.get("session_id"), str) else None,
        response_type=raw.get("response_type") if isinstance(raw.get("response_type"), str) else None,
        waiting_for_clarification=_safe_bool_or_none(raw.get("waiting_for_clarification")),
        next_steps=next_steps,
        usage=usage,
        raw=raw,
    )


def model_from_payload(payload: Mapping[str, Any]) -> ModelInfo:
    raw = dict(payload)
    model_id = raw.get("id")
    if not isinstance(model_id, str) or not model_id:
        raise ValueError("Model payload missing 'id'.")

    return ModelInfo(
        id=model_id,
        object=raw.get("object") if isinstance(raw.get("object"), str) else None,
        created=_safe_int(raw.get("created")),
        owned_by=raw.get("owned_by") if isinstance(raw.get("owned_by"), str) else None,
        raw=raw,
    )


def session_from_payload(payload: Mapping[str, Any]) -> SessionInfo:
    raw = dict(payload)
    session_id = raw.get("session_id")
    if not isinstance(session_id, str) or not session_id:
        raise ValueError("Session payload missing 'session_id'.")

    return SessionInfo(
        session_id=session_id,
        ttl_seconds=_safe_int(raw.get("ttl_seconds")),
        created_at=raw.get("created_at") if isinstance(raw.get("created_at"), str) else None,
        raw=raw,
    )


def session_delete_from_payload(payload: Mapping[str, Any]) -> SessionDeleteResult:
    raw = dict(payload)
    session_id = raw.get("session_id")
    if not isinstance(session_id, str) or not session_id:
        raise ValueError("Session delete payload missing 'session_id'.")

    return SessionDeleteResult(
        session_id=session_id,
        cleared=bool(raw.get("cleared")),
        cleared_at=raw.get("cleared_at") if isinstance(raw.get("cleared_at"), str) else None,
        raw=raw,
    )


def ingest_from_payload(payload: Mapping[str, Any]) -> IngestResponse:
    raw = dict(payload)
    status = raw.get("status")
    if not isinstance(status, str) or not status:
        raise ValueError("Ingest response missing 'status'.")

    return IngestResponse(
        status=status,
        raw=raw,
    )
