"""Discord integration via Discord Bot API."""

import os
from urllib.parse import quote

import httpx

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


def _headers() -> dict:
    token = os.environ.get("DISCORD_BOT_TOKEN")
    if not token:
        raise ValueError(
            "DISCORD_BOT_TOKEN not set. Create a bot at https://discord.com/developers/applications, "
            "go to Bot tab, reset token, enable Message Content Intent, "
            "then invite the bot to your server."
        )
    return {
        "Authorization": f"Bot {token}",
        "Content-Type": "application/json",
    }


async def handler(params: dict) -> dict:
    """Handle Discord operations."""
    action = params["action"]
    headers = _headers()

    try:
        async with httpx.AsyncClient(timeout=30) as client:
            if action == "send_message":
                return await _send_message(client, headers, params)
            elif action == "react":
                return await _react(client, headers, params)
            elif action == "list_channels":
                return await _list_channels(client, headers, params)
            elif action == "read_messages":
                return await _read_messages(client, headers, params)
            else:
                return {"success": False, "message": f"Unknown action: {action}", "data": {}}
    except ValueError:
        raise
    except httpx.HTTPStatusError as e:
        error_body = e.response.text[:300]
        return {"success": False, "message": f"Discord API error ({e.response.status_code}): {error_body}", "data": {}}
    except Exception as e:
        return {"success": False, "message": f"Error: {e}", "data": {}}


async def _send_message(client: httpx.AsyncClient, headers: dict, params: dict) -> dict:
    channel_id = params.get("channel_id")
    content = params.get("content")
    if not channel_id or not content:
        raise ValueError("'channel_id' and 'content' are required for send_message")

    resp = await client.post(
        f"{DISCORD_API}/channels/{channel_id}/messages",
        headers=headers,
        json={"content": content},
    )
    resp.raise_for_status()
    data = resp.json()

    return {
        "success": True,
        "message": f"Message sent to channel {channel_id}",
        "data": {"id": data["id"], "channel_id": data["channel_id"]},
    }


async def _react(client: httpx.AsyncClient, headers: dict, params: dict) -> dict:
    channel_id = params.get("channel_id")
    message_id = params.get("message_id")
    emoji = params.get("emoji")
    if not channel_id or not message_id or not emoji:
        raise ValueError("'channel_id', 'message_id', and 'emoji' are required for react")

    encoded_emoji = quote(emoji)
    resp = await client.put(
        f"{DISCORD_API}/channels/{channel_id}/messages/{message_id}/reactions/{encoded_emoji}/@me",
        headers=headers,
    )
    resp.raise_for_status()

    return {"success": True, "message": f"Added {emoji} reaction", "data": {}}


async def _list_channels(client: httpx.AsyncClient, headers: dict, params: dict) -> dict:
    guild_id = params.get("guild_id")

    # If no guild_id, get first guild the bot is in
    if not guild_id:
        resp = await client.get(f"{DISCORD_API}/users/@me/guilds", headers=headers)
        resp.raise_for_status()
        guilds = resp.json()
        if not guilds:
            return {"success": False, "message": "Bot is not in any servers", "data": {}}
        guild_id = guilds[0]["id"]

    resp = await client.get(f"{DISCORD_API}/guilds/{guild_id}/channels", headers=headers)
    resp.raise_for_status()
    data = resp.json()

    # Filter to text channels (type 0) and announcement channels (type 5)
    channels = [
        {
            "id": ch["id"],
            "name": ch.get("name", ""),
            "type": "text" if ch["type"] == 0 else "announcement" if ch["type"] == 5 else f"type_{ch['type']}",
            "topic": ch.get("topic", ""),
        }
        for ch in data
        if ch.get("type") in (0, 5)
    ]
    return {
        "success": True,
        "message": f"Found {len(channels)} text channel(s) in guild {guild_id}",
        "data": {"guild_id": guild_id, "channels": channels},
    }


async def _read_messages(client: httpx.AsyncClient, headers: dict, params: dict) -> dict:
    channel_id = params.get("channel_id")
    if not channel_id:
        raise ValueError("'channel_id' is required for read_messages")

    limit = min(int(params.get("limit") or 10), 100)

    resp = await client.get(
        f"{DISCORD_API}/channels/{channel_id}/messages",
        headers=headers,
        params={"limit": limit},
    )
    resp.raise_for_status()
    data = resp.json()

    messages = [
        {
            "id": msg["id"],
            "author": msg.get("author", {}).get("username", ""),
            "content": f"<external_message>{msg.get('content', '')}</external_message>",
            "timestamp": msg.get("timestamp", ""),
        }
        for msg in data
    ]
    return {
        "success": True,
        "message": f"Retrieved {len(messages)} message(s)",
        "data": {"messages": messages},
    }
