"""Message tool for sending messages to users."""

import uuid
from typing import Any, Awaitable, Callable

from madpod_agent.agent.tools.base import Tool
from madpod_agent.bus.events import OutboundMessage


class MessageTool(Tool):
    """Tool to send messages to users on chat channels."""

    def __init__(
        self,
        send_callback: Callable[[OutboundMessage], Awaitable[None]] | None = None,
        default_channel: str = "",
        default_chat_id: str = "",
        default_message_id: str | None = None,
        default_metadata: dict[str, Any] | None = None,
    ):
        self._send_callback = send_callback
        self._default_channel = default_channel
        self._default_chat_id = default_chat_id
        self._default_message_id = default_message_id
        self._default_metadata = dict(default_metadata or {})
        self._sent_in_turn: bool = False

    def set_context(
        self,
        channel: str,
        chat_id: str,
        message_id: str | None = None,
        metadata: dict[str, Any] | None = None,
    ) -> None:
        """Set the current message context."""
        self._default_channel = channel
        self._default_chat_id = chat_id
        self._default_message_id = message_id
        self._default_metadata = dict(metadata or {})
        if message_id and not str(self._default_metadata.get("assignment_message_id") or "").strip():
            self._default_metadata["assignment_message_id"] = message_id

    def set_send_callback(self, callback: Callable[[OutboundMessage], Awaitable[None]]) -> None:
        """Set the callback for sending messages."""
        self._send_callback = callback

    def start_turn(self) -> None:
        """Reset per-turn send tracking."""
        self._sent_in_turn = False

    @property
    def name(self) -> str:
        return "message"

    @property
    def description(self) -> str:
        return "Send a message to the user. Use this when you want to communicate something."

    @property
    def parameters(self) -> dict[str, Any]:
        return {
            "type": "object",
            "properties": {
                "content": {
                    "type": "string",
                    "description": "The message content to send"
                },
                "channel": {
                    "type": "string",
                    "description": "Optional: target channel (telegram, discord, etc.)"
                },
                "chat_id": {
                    "type": "string",
                    "description": "Optional: target chat/user ID"
                },
                "media": {
                    "type": "array",
                    "items": {"type": "string"},
                    "description": "Optional: list of file paths to attach (images, audio, documents)"
                },
                "progress": {
                    "type": "boolean",
                    "description": "Deprecated: for Madpod this maps to an activity update instead of a deliverable."
                },
                "kind": {
                    "type": "string",
                    "enum": ["acknowledgement", "activity", "deliverable", "intervention"],
                    "description": "Optional: explicit Madpod message kind for deterministic task routing."
                },
                "deliverable_payload": {
                    "type": "object",
                    "description": "Optional: structured Madpod deliverable envelope with completion_state, summary, artifacts, evidence, and missing_items.",
                },
            },
            "required": ["content"]
        }

    async def execute(
        self,
        content: str,
        channel: str | None = None,
        chat_id: str | None = None,
        message_id: str | None = None,
        media: list[str] | None = None,
        progress: bool = True,
        kind: str | None = None,
        round_id: str | None = None,
        subtask_id: str | None = None,
        in_reply_to: str | None = None,
        directive_id: str | None = None,
        deliverable_payload: dict[str, Any] | None = None,
        **kwargs: Any
    ) -> str:
        channel = channel or self._default_channel
        chat_id = chat_id or self._default_chat_id
        context = dict(self._default_metadata or {})
        assignment_message_id = str(
            context.get("assignment_message_id")
            or context.get("directive_id")
            or self._default_message_id
            or ""
        ).strip() or None
        upstream_in_reply_to = str(context.get("in_reply_to") or "").strip() or None
        reply_target = in_reply_to or assignment_message_id or upstream_in_reply_to
        outbound_message_id = message_id or uuid.uuid4().hex

        if not channel or not chat_id:
            return "Error: No target channel/chat specified"

        if not self._send_callback:
            return "Error: Message sending not configured"

        resolved_kind = (kind or "").strip().lower() or None
        if resolved_kind not in {"acknowledgement", "activity", "deliverable", "intervention", None}:
            return f"Error: Unsupported message kind '{resolved_kind}'"
        if resolved_kind is None and channel == "madpod":
            resolved_kind = "deliverable" if isinstance(deliverable_payload, dict) else ("activity" if progress else "deliverable")

        metadata: dict[str, Any] = {
            "message_id": outbound_message_id,
        }
        resolved_round_id = round_id or context.get("round_id")
        if resolved_round_id:
            metadata["round_id"] = resolved_round_id
        resolved_subtask_id = subtask_id or context.get("subtask_id")
        if resolved_subtask_id:
            metadata["subtask_id"] = resolved_subtask_id
        resolved_directive_id = directive_id or context.get("directive_id") or assignment_message_id
        if resolved_directive_id:
            metadata["directive_id"] = resolved_directive_id
        if reply_target:
            metadata["in_reply_to"] = reply_target
        if upstream_in_reply_to and upstream_in_reply_to != reply_target:
            metadata["origin_in_reply_to"] = upstream_in_reply_to
        if resolved_kind:
            metadata["message_kind"] = resolved_kind
        if resolved_kind == "activity":
            metadata["action"] = str(kwargs.get("action") or "status_update")
            metadata["summary"] = str(kwargs.get("summary") or content).strip() or content
            metadata["thought"] = str(kwargs.get("thought") or content).strip() or content
        elif progress:
            metadata["_progress"] = True
        if isinstance(deliverable_payload, dict):
            metadata["deliverable_payload"] = deliverable_payload

        msg = OutboundMessage(
            channel=channel,
            chat_id=chat_id,
            content=content,
            media=media or [],
            metadata=metadata,
        )

        try:
            await self._send_callback(msg)
            same_target = channel == self._default_channel and chat_id == self._default_chat_id
            if same_target and (
                resolved_kind in {"deliverable", "intervention"}
                or (resolved_kind is None and not progress)
            ):
                self._sent_in_turn = True
            media_info = f" with {len(media)} attachments" if media else ""
            return f"Message sent to {channel}:{chat_id}{media_info}"
        except Exception as e:
            return f"Error sending message: {str(e)}"
