"""Gateway message shapes."""

from __future__ import annotations

from dataclasses import dataclass, field
from datetime import datetime, timezone
import uuid

from memnixa.identity import OWNER_USER_ID


def _new_id() -> str:
    return uuid.uuid4().hex


def _now_utc() -> str:
    return datetime.now(timezone.utc).isoformat()


@dataclass(slots=True)
class InboundMessageContext:
    """Normalized gateway message."""

    session_id: str
    raw_body: str
    body_for_agent: str
    run_id: str | None = field(default_factory=_new_id)
    message_id: str | None = field(default_factory=_new_id)
    received_at: str | None = field(default_factory=_now_utc)
    source_mode: str = "unknown"
    channel: str | None = None
    launch_cwd: str | None = None
    entrypoint_path: str | None = None
    python_executable: str | None = None
    capabilities: tuple[str, ...] = field(default_factory=tuple)
    actor_identity_status: str = "unknown"
    actor_user_id: str | None = None
    actor_role: str = "unknown"
    actor_external_id: str | None = None
    actor_is_owner: bool = False

    def __post_init__(self) -> None:
        if not self.run_id:
            self.run_id = _new_id()
        if not self.message_id:
            self.message_id = _new_id()
        if not self.received_at:
            self.received_at = _now_utc()
        if not isinstance(self.capabilities, tuple):
            self.capabilities = tuple(str(item) for item in self.capabilities)
        self.actor_identity_status = str(
            self.actor_identity_status or "unknown"
        ).strip() or "unknown"
        self.actor_role = str(self.actor_role or "unknown").strip() or "unknown"
        if self.actor_user_id is not None:
            self.actor_user_id = str(self.actor_user_id).strip() or None
        if self.actor_external_id is not None:
            self.actor_external_id = str(self.actor_external_id).strip() or None
        self.actor_is_owner = bool(self.actor_is_owner)
        if (
            (self.channel or "").strip().lower() == "cli"
            and self.actor_identity_status == "unknown"
            and self.actor_user_id is None
            and self.actor_external_id is None
            and not self.actor_is_owner
        ):
            self.actor_identity_status = "owner"
            self.actor_user_id = OWNER_USER_ID
            self.actor_role = "owner"
            self.actor_external_id = OWNER_USER_ID
            self.actor_is_owner = True
