"""Discord webhook client."""

from __future__ import annotations

import asyncio
import logging
from typing import Any, Final

import aiohttp

from ..http_base import HttpProviderClient

_LOGGER = logging.getLogger(__name__)

# Discord API constraints (per webhook docs).
MAX_CONTENT_LENGTH: Final = 2000
MAX_USERNAME_LENGTH: Final = 80


class DiscordClient(HttpProviderClient):
    """Sends messages via Discord webhook URLs."""

    def __init__(self, session: aiohttp.ClientSession) -> None:
        super().__init__(session, provider_name="discord")

    async def send(
        self,
        webhook_url: str,
        message: str,
        username: str | None = None,
        avatar_url: str | None = None,
    ) -> dict[str, Any]:
        """Send a message to a Discord webhook.

        If message exceeds 2000 chars, it's split into chunks.
        """
        if not webhook_url:
            return {"success": False, "error": "Missing webhook_url"}
        if username and len(username) > MAX_USERNAME_LENGTH:
            return {"success": False, "error": f"username exceeds {MAX_USERNAME_LENGTH} chars"}

        chunks = _split_message(message, MAX_CONTENT_LENGTH)
        for chunk in chunks:
            payload: dict[str, Any] = {"content": chunk}
            if username:
                payload["username"] = username
            if avatar_url:
                payload["avatar_url"] = avatar_url

            result = await self.request("POST", webhook_url, json=payload)
            if not result.get("success"):
                return result

            if len(chunks) > 1:
                await asyncio.sleep(0.5)

        return {"success": True}


def _split_message(text: str, limit: int) -> list[str]:
    """Split message into chunks respecting the character limit.

    Drops chunks that contain only whitespace — Discord rejects those.
    """
    if len(text) <= limit:
        return [text]
    chunks: list[str] = []
    while text:
        if len(text) <= limit:
            piece = text
            text = ""
        else:
            split_at = text.rfind("\n", 0, limit)
            if split_at <= 0:
                split_at = limit
            piece = text[:split_at]
            text = text[split_at:].lstrip("\n")
        if piece.strip():
            chunks.append(piece)
    return chunks or [text]
