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

from typing import Any, Awaitable, Callable

from sarathy.agent.tools.base import Tool
from sarathy.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,
        channels_config: Any = 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._channels_config = channels_config
        self._turn_sends: list[
            tuple[str, str]
        ] = []  # List of (channel, chat_id) tuples sent this turn
        self._response_metadata: dict[str, Any] = {}

    def set_context(self, channel: str, chat_id: str, message_id: str | None = None) -> None:
        """Set the current message context."""
        self._default_channel = channel
        self._default_chat_id = chat_id
        self._default_message_id = message_id

    def set_response_metadata(self, metadata: dict[str, Any]) -> None:
        """Set metadata for response (verbose, stats, etc)."""
        self._response_metadata = metadata

    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._turn_sends = []
        self._response_metadata = {}

    def get_turn_sends(self) -> list[tuple[str, str]]:
        """Return list of (channel, chat_id) tuples sent this turn."""
        return self._turn_sends.copy()

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

    def _get_enabled_channels(self) -> list[str]:
        """Get list of enabled channel names from config."""
        if not self._channels_config:
            return []
        channels = []
        config = self._channels_config
        if getattr(getattr(config, "telegram", None), "enabled", False):
            channels.append("telegram")
        if getattr(getattr(config, "discord", None), "enabled", False):
            channels.append("discord")
        if getattr(getattr(config, "email", None), "enabled", False):
            channels.append("email")
        return channels

    @property
    def description(self) -> str:
        enabled_channels = self._get_enabled_channels()
        if enabled_channels:
            channel_list = ", ".join(enabled_channels)
            return f"Send a message to the user. Use this when you want to communicate something. Available channels: {channel_list}"
        return "Send a message to the user. Use this when you want to communicate something."

    @property
    def parameters(self) -> dict[str, Any]:
        enabled_channels = self._get_enabled_channels()
        has_email = "email" in enabled_channels

        chat_id_desc = "Required for email channel (must be email address like user@example.com). For telegram/discord, use numeric user/chat ID."
        if enabled_channels:
            chat_id_desc = (
                f"Target {'email address' if has_email else 'chat/user ID'}. " + chat_id_desc
            )

        return {
            "type": "object",
            "properties": {
                "content": {"type": "string", "description": "The message content to send"},
                "channel": {
                    "type": "string",
                    "description": f"Target channel ({', '.join(enabled_channels)})"
                    if enabled_channels
                    else "Target channel (telegram, discord, email, etc.)",
                },
                "chat_id": {"type": "string", "description": chat_id_desc},
                "media": {
                    "type": "array",
                    "items": {"type": "string"},
                    "description": "Optional: list of file paths to attach (images, audio, documents)",
                },
            },
            "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,
        **kwargs: Any,
    ) -> str:
        # Handle case where model passes a dict instead of string
        if isinstance(content, dict):
            # Extract values from dict if passed
            content_dict = content
            channel = channel or content_dict.get("channel")
            chat_id = chat_id or content_dict.get("chat_id")
            content = content_dict.get("content", str(content_dict))
            media = media or content_dict.get("media", [])

        channel = channel or self._default_channel
        chat_id = chat_id or self._default_chat_id
        message_id = message_id or self._default_message_id

        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"

        # Append verbose stats if enabled
        if self._response_metadata.get("_verbose") and self._response_metadata.get("_stats"):
            stats = self._response_metadata["_stats"]
            tps = stats.get("tokens_per_sec", 0)
            tokens = stats.get("total_tokens", 0)
            if tps > 0 and tokens > 0:
                content = f"{content}\n\n⚡ {tokens} tokens @ {tps:.1f} tokens/sec"

        msg = OutboundMessage(
            channel=channel,
            chat_id=chat_id,
            content=content,
            media=media or [],
            metadata={
                "message_id": message_id,
            },
        )

        try:
            await self._send_callback(msg)
            # Track the actual send target
            self._turn_sends.append((channel, chat_id))
            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)}"
