"""Discord message delivery helpers.

Provides fire-and-forget helpers that POST Discord embeds to the REST API
using a bot token — no running WebSocket gateway is required.

``gateway`` throughout this module refers to any object (or dict) that exposes
a ``bot_token`` attribute/key.  This is compatible with both the plain dicts
returned by the discord_configs REST API and any future discord.py Client
wrapper that stores the token.
"""

from __future__ import annotations

import logging
from typing import Any

import httpx

logger = logging.getLogger(__name__)

DISCORD_API_BASE = "https://discord.com/api/v10"


def _token(gateway: Any) -> str:
    """Extract the bot token from a gateway object or dict."""
    if isinstance(gateway, dict):
        return gateway.get("bot_token", "")
    return getattr(gateway, "bot_token", "")


async def send_to_channel(
    gateway: Any,
    channel_id: str,
    embed: dict,
    content: str = "",
) -> bool:
    """Send a Discord embed to a guild channel.

    Args:
        gateway: A discord config dict (or object) with a ``bot_token`` field.
        channel_id: Discord channel snowflake ID (string).
        embed: A Discord embed dict as returned by :func:`peon_mcp.discord.embeds.build_embed`.
        content: Optional plain-text message to accompany the embed.

    Returns:
        ``True`` if the message was delivered successfully (HTTP 200), ``False``
        otherwise.  Never raises — all errors are caught and logged.
    """
    token = _token(gateway)
    if not token:
        logger.warning("send_to_channel: no bot_token in gateway, skipping delivery")
        return False

    headers = {
        "Authorization": f"Bot {token}",
        "Content-Type": "application/json",
    }
    payload: dict = {"embeds": [embed]}
    if content:
        payload["content"] = content

    try:
        async with httpx.AsyncClient(timeout=10.0) as client:
            response = await client.post(
                f"{DISCORD_API_BASE}/channels/{channel_id}/messages",
                json=payload,
                headers=headers,
            )
            if response.status_code in (200, 201):
                return True
            logger.warning(
                "send_to_channel: Discord API returned %d for channel %s: %s",
                response.status_code,
                channel_id,
                response.text[:200],
            )
            return False
    except httpx.TimeoutException:
        logger.warning("send_to_channel: request timed out for channel %s", channel_id)
        return False
    except Exception as exc:
        logger.warning("send_to_channel: unexpected error for channel %s: %s", channel_id, exc)
        return False


async def send_to_user(
    gateway: Any,
    user_id: str,
    embed: dict,
    content: str = "",
) -> bool:
    """Send a Discord embed to a user via DM.

    Opens (or reuses) a DM channel with the user, then sends the embed.

    Args:
        gateway: A discord config dict (or object) with a ``bot_token`` field.
        user_id: Discord user snowflake ID (string).
        embed: A Discord embed dict as returned by :func:`peon_mcp.discord.embeds.build_embed`.
        content: Optional plain-text message to accompany the embed.

    Returns:
        ``True`` if the message was delivered successfully, ``False`` otherwise.
        Never raises — all errors are caught and logged.
    """
    token = _token(gateway)
    if not token:
        logger.warning("send_to_user: no bot_token in gateway, skipping delivery")
        return False

    headers = {
        "Authorization": f"Bot {token}",
        "Content-Type": "application/json",
    }

    try:
        async with httpx.AsyncClient(timeout=10.0) as client:
            # Step 1: Create (or retrieve) the DM channel
            dm_response = await client.post(
                f"{DISCORD_API_BASE}/users/@me/channels",
                json={"recipient_id": user_id},
                headers=headers,
            )
            if dm_response.status_code not in (200, 201):
                logger.warning(
                    "send_to_user: failed to open DM channel for user %s: HTTP %d %s",
                    user_id,
                    dm_response.status_code,
                    dm_response.text[:200],
                )
                return False

            dm_channel_id = dm_response.json().get("id")
            if not dm_channel_id:
                logger.warning("send_to_user: DM channel response missing 'id' for user %s", user_id)
                return False

            # Step 2: Send to the DM channel
            msg_payload: dict = {"embeds": [embed]}
            if content:
                msg_payload["content"] = content

            msg_response = await client.post(
                f"{DISCORD_API_BASE}/channels/{dm_channel_id}/messages",
                json=msg_payload,
                headers=headers,
            )
            if msg_response.status_code in (200, 201):
                return True
            logger.warning(
                "send_to_user: Discord API returned %d for DM channel %s (user %s): %s",
                msg_response.status_code,
                dm_channel_id,
                user_id,
                msg_response.text[:200],
            )
            return False
    except httpx.TimeoutException:
        logger.warning("send_to_user: request timed out for user %s", user_id)
        return False
    except Exception as exc:
        logger.warning("send_to_user: unexpected error for user %s: %s", user_id, exc)
        return False
