"""Structured message schemas for MRP request/response, events, and status."""

from __future__ import annotations

from dataclasses import dataclass
from typing import Any

from mrp.models import Message

# --- Content Type Constants ---

REQUEST_CONTENT_TYPE = "application/x-mrp-request+json"
RESPONSE_CONTENT_TYPE = "application/x-mrp-response+json"
EVENT_CONTENT_TYPE = "application/x-mrp-event+json"
STATUS_CONTENT_TYPE = "application/x-mrp-status+json"


# --- Schema Types ---


@dataclass
class MRPResponseError:
    code: str
    message: str

    def to_dict(self) -> dict[str, Any]:
        return {"code": self.code, "message": self.message}


@dataclass
class MRPRequest:
    action: str
    params: dict[str, Any]
    response_format: str | None = None

    def to_dict(self) -> dict[str, Any]:
        d: dict[str, Any] = {"action": self.action, "params": self.params}
        if self.response_format is not None:
            d["response_format"] = self.response_format
        return d


@dataclass
class MRPResponse:
    status: str  # "ok" or "error"
    result: dict[str, Any] | None = None
    error: MRPResponseError | None = None

    def to_dict(self) -> dict[str, Any]:
        d: dict[str, Any] = {"status": self.status}
        if self.result is not None:
            d["result"] = self.result
        if self.error is not None:
            d["error"] = self.error.to_dict()
        return d


@dataclass
class MRPEvent:
    event: str
    data: dict[str, Any] | None = None

    def to_dict(self) -> dict[str, Any]:
        d: dict[str, Any] = {"event": self.event}
        if self.data is not None:
            d["data"] = self.data
        return d


@dataclass
class MRPStatus:
    progress: float | None = None
    stage: str | None = None
    detail: str | None = None

    def to_dict(self) -> dict[str, Any]:
        d: dict[str, Any] = {}
        if self.progress is not None:
            d["progress"] = self.progress
        if self.stage is not None:
            d["stage"] = self.stage
        if self.detail is not None:
            d["detail"] = self.detail
        return d


# --- Builder Functions ---


def create_request(
    action: str,
    params: dict[str, Any],
    response_format: str | None = None,
) -> MRPRequest:
    """Create an MRP request schema object."""
    return MRPRequest(action=action, params=params, response_format=response_format)


def create_ok_response(result: dict[str, Any]) -> MRPResponse:
    """Create a successful MRP response."""
    return MRPResponse(status="ok", result=result)


def create_error_response(code: str, message: str) -> MRPResponse:
    """Create an error MRP response."""
    return MRPResponse(status="error", error=MRPResponseError(code=code, message=message))


def create_event(event: str, data: dict[str, Any] | None = None) -> MRPEvent:
    """Create an MRP event."""
    return MRPEvent(event=event, data=data)


def create_status(
    progress: float | None = None,
    stage: str | None = None,
    detail: str | None = None,
) -> MRPStatus:
    """Create an MRP status update."""
    return MRPStatus(progress=progress, stage=stage, detail=detail)


# --- Parser Functions ---


def parse_request(body: Any) -> MRPRequest | None:
    """Parse a dict as an MRPRequest. Returns None on invalid input."""
    if not isinstance(body, dict):
        return None
    action = body.get("action")
    if not isinstance(action, str):
        return None
    params = body.get("params")
    if params is None:
        params = {}
    if not isinstance(params, dict):
        return None
    response_format = body.get("response_format")
    if response_format is not None and not isinstance(response_format, str):
        response_format = None
    return MRPRequest(action=action, params=params, response_format=response_format)


def parse_response(body: Any) -> MRPResponse | None:
    """Parse a dict as an MRPResponse. Returns None on invalid input."""
    if not isinstance(body, dict):
        return None
    status = body.get("status")
    if status not in ("ok", "error"):
        return None
    result = body.get("result")
    error_data = body.get("error")
    error = None
    if isinstance(error_data, dict):
        error = MRPResponseError(
            code=error_data.get("code", ""),
            message=error_data.get("message", ""),
        )
    return MRPResponse(status=status, result=result, error=error)


def parse_event(body: Any) -> MRPEvent | None:
    """Parse a dict as an MRPEvent. Returns None on invalid input."""
    if not isinstance(body, dict):
        return None
    event = body.get("event")
    if not isinstance(event, str):
        return None
    data = body.get("data")
    return MRPEvent(event=event, data=data)


def parse_status(body: Any) -> MRPStatus | None:
    """Parse a dict as an MRPStatus. Returns None on invalid input."""
    if not isinstance(body, dict):
        return None
    return MRPStatus(
        progress=body.get("progress"),
        stage=body.get("stage"),
        detail=body.get("detail"),
    )


# --- Message Helper Functions ---


def is_request(msg: Message) -> bool:
    """Check if a message is an MRP request."""
    return msg.content_type == REQUEST_CONTENT_TYPE


def is_response(msg: Message) -> bool:
    """Check if a message is an MRP response."""
    return msg.content_type == RESPONSE_CONTENT_TYPE


def is_event(msg: Message) -> bool:
    """Check if a message is an MRP event."""
    return msg.content_type == EVENT_CONTENT_TYPE


def is_status(msg: Message) -> bool:
    """Check if a message is an MRP status update."""
    return msg.content_type == STATUS_CONTENT_TYPE


def as_request(msg: Message) -> MRPRequest | None:
    """Parse message body as MRPRequest if content type matches. Returns None otherwise."""
    if msg.content_type != REQUEST_CONTENT_TYPE:
        return None
    return parse_request(msg.body)


def as_response(msg: Message) -> MRPResponse | None:
    """Parse message body as MRPResponse if content type matches. Returns None otherwise."""
    if msg.content_type != RESPONSE_CONTENT_TYPE:
        return None
    return parse_response(msg.body)


def as_event(msg: Message) -> MRPEvent | None:
    """Parse message body as MRPEvent if content type matches. Returns None otherwise."""
    if msg.content_type != EVENT_CONTENT_TYPE:
        return None
    return parse_event(msg.body)


def as_status(msg: Message) -> MRPStatus | None:
    """Parse message body as MRPStatus if content type matches. Returns None otherwise."""
    if msg.content_type != STATUS_CONTENT_TYPE:
        return None
    return parse_status(msg.body)
