"""Minimal message bus for gateway-style host integration."""

from __future__ import annotations

import asyncio
from dataclasses import dataclass, field
from datetime import datetime, timezone
from typing import Any
from uuid import uuid4


@dataclass(slots=True)
class ChannelIdentity:
    """Normalized channel routing identity.

    `channel_id` is the Beaver adapter instance id, not the platform kind.
    """

    channel_id: str
    kind: str
    account_id: str
    peer_id: str
    thread_id: str | None = None
    peer_type: str = "unknown"
    user_id: str | None = None
    message_id: str | None = None

    def validation_error(self) -> str | None:
        if not self.channel_id.strip():
            return "channel_id is required"
        if not self.account_id.strip():
            return "account_id is required"
        if not self.peer_id.strip():
            return "peer_id is required"
        return None

    def session_id(self) -> str:
        parts = [self.channel_id, self.account_id, self.peer_id]
        if self.thread_id:
            parts.append(self.thread_id)
        return ":".join(_clean_session_part(part) for part in parts)

    def dedupe_key(self) -> str | None:
        if not self.message_id:
            return None
        return f"{self.session_id()}:{_clean_session_part(self.message_id)}"


def _clean_session_part(value: str) -> str:
    cleaned = str(value).strip()
    if not cleaned:
        return "unknown"
    return cleaned.replace(":", "_")


@dataclass(slots=True)
class InboundMessage:
    """A minimal inbound message accepted by the gateway bridge."""

    channel: str
    content: str
    content_type: str = "text"
    channel_identity: ChannelIdentity | None = None
    session_id: str | None = None
    user_id: str | None = None
    title: str | None = None
    execution_context: str | None = None
    model: str | None = None
    provider_name: str | None = None
    embedding_model: str | None = None
    message_id: str = field(default_factory=lambda: str(uuid4()))
    metadata: dict[str, Any] = field(default_factory=dict)
    timestamp: datetime = field(default_factory=lambda: datetime.now(timezone.utc))


@dataclass(slots=True)
class OutboundMessage:
    """A minimal outbound message produced by the gateway bridge."""

    channel: str
    content: str
    session_id: str | None
    finish_reason: str
    content_type: str = "text"
    channel_identity: ChannelIdentity | None = None
    message_id: str = field(default_factory=lambda: str(uuid4()))
    run_id: str | None = None
    provider_name: str | None = None
    model: str | None = None
    usage: dict[str, Any] = field(default_factory=dict)
    metadata: dict[str, Any] = field(default_factory=dict)
    timestamp: datetime = field(default_factory=lambda: datetime.now(timezone.utc))


class MessageBus:
    """Minimal async message bus with inbound/outbound queues."""

    def __init__(self) -> None:
        self.inbound: asyncio.Queue[InboundMessage] = asyncio.Queue()
        self.outbound: asyncio.Queue[OutboundMessage] = asyncio.Queue()

    async def publish_inbound(self, message: InboundMessage) -> None:
        await self.inbound.put(message)

    async def consume_inbound(self) -> InboundMessage:
        return await self.inbound.get()

    async def publish_outbound(self, message: OutboundMessage) -> None:
        await self.outbound.put(message)

    async def consume_outbound(self) -> OutboundMessage:
        return await self.outbound.get()

    @property
    def inbound_size(self) -> int:
        return self.inbound.qsize()

    @property
    def outbound_size(self) -> int:
        return self.outbound.qsize()
