"""Simple Telegram bot interface for brawny.

Provides direct access to the Telegram Bot API for sending messages
from anywhere in your job code. This is a thin wrapper that defers
to the Telegram API directly.

Usage in jobs:

    from brawny.telegram import telegram

    class MyJob(Job):
        def check(self, ctx):
            # Send a simple message
            telegram.send("Something happened!")

            # Send with markdown
            telegram.send("*Bold* and _italic_", parse_mode="Markdown")

            # Send with HTML
            telegram.send("<b>Bold</b>", parse_mode="HTML")

            # Disable link preview
            telegram.send("Check https://example.com", disable_preview=True)

            # Silent notification
            telegram.send("Low priority update", silent=True)

Configuration:
    Set these environment variables:
    - TELEGRAM_BOT_TOKEN: Your bot token from @BotFather
    - TELEGRAM_CHAT_ID: Chat ID to send to

    Or configure in config.yaml:
        telegram_bot_token: "123456:ABC..."
        telegram_chat_id: "-1001234567890"
"""

from __future__ import annotations

import os
from typing import Any

import requests

from brawny.logging import get_logger

logger = get_logger(__name__)

# Telegram API limits
MAX_MESSAGE_LENGTH = 4096
TRUNCATION_SUFFIX = "\n...[truncated]"


def _truncate_message(text: str, max_length: int = MAX_MESSAGE_LENGTH) -> str:
    """Truncate message to fit Telegram's limit."""
    if len(text) <= max_length:
        return text
    return text[: max_length - len(TRUNCATION_SUFFIX)] + TRUNCATION_SUFFIX


class TelegramBot:
    """Simple Telegram Bot API wrapper.

    Provides direct access to common Telegram Bot API methods.
    All methods mirror the Telegram API parameters.

    See: https://core.telegram.org/bots/api
    """

    def __init__(
        self,
        token: str | None = None,
        chat_id: str | None = None,
        timeout: int = 30,
    ) -> None:
        """Initialize Telegram bot.

        Args:
            token: Bot token. Defaults to TELEGRAM_BOT_TOKEN env var.
            chat_id: Default chat ID. Defaults to TELEGRAM_CHAT_ID env var.
            timeout: Request timeout in seconds.
        """
        self._token = token or os.environ.get("TELEGRAM_BOT_TOKEN")
        self._default_chat_id = chat_id or os.environ.get("TELEGRAM_CHAT_ID")
        self._timeout = timeout

    @property
    def configured(self) -> bool:
        """Check if bot is configured with token and chat_id."""
        return bool(self._token and self._default_chat_id)

    @property
    def api_url(self) -> str:
        """Base URL for Telegram API."""
        return f"https://api.telegram.org/bot{self._token}"

    def _request(self, method: str, **params: Any) -> dict | None:
        """Make a request to the Telegram API.

        Args:
            method: API method name (e.g., "sendMessage")
            **params: Method parameters

        Returns:
            API response dict, or None on failure
        """
        if not self._token:
            logger.warning("telegram.not_configured", message="No bot token set")
            return None

        # Filter out None values
        params = {k: v for k, v in params.items() if v is not None}

        try:
            response = requests.post(
                f"{self.api_url}/{method}",
                json=params,
                timeout=self._timeout,
            )
            response.raise_for_status()
            result = response.json()

            if not result.get("ok"):
                logger.error(
                    "telegram.api_error",
                    method=method,
                    error=result.get("description"),
                )
                return None

            return result.get("result")

        except requests.exceptions.RequestException as e:
            logger.error("telegram.request_failed", method=method, error=str(e)[:200])
            return None

    def send(
        self,
        text: str,
        chat_id: str | int | None = None,
        parse_mode: str | None = None,
        disable_preview: bool = True,
        silent: bool = False,
        reply_to: int | None = None,
    ) -> dict | None:
        """Send a text message.

        This is the main method for sending messages. It wraps the
        Telegram sendMessage API.

        Args:
            text: Message text (up to 4096 characters)
            chat_id: Target chat. Defaults to configured chat_id.
            parse_mode: "Markdown", "MarkdownV2", or "HTML". None for plain text.
            disable_preview: Disable link previews in the message.
            silent: Send without notification sound.
            reply_to: Message ID to reply to.

        Returns:
            Message object from Telegram API, or None on failure.

        Examples:
            # Plain text
            telegram.send("Hello world!")

            # Markdown
            telegram.send("*bold* _italic_ `code`", parse_mode="Markdown")

            # HTML
            telegram.send("<b>bold</b> <i>italic</i>", parse_mode="HTML")
        """
        return self._request(
            "sendMessage",
            chat_id=chat_id or self._default_chat_id,
            text=_truncate_message(text),
            parse_mode=parse_mode,
            disable_web_page_preview=disable_preview,
            disable_notification=silent,
            reply_to_message_id=reply_to,
        )

    def send_photo(
        self,
        photo: str,
        caption: str | None = None,
        chat_id: str | int | None = None,
        parse_mode: str | None = None,
    ) -> dict | None:
        """Send a photo by URL.

        Args:
            photo: Photo URL or file_id
            caption: Optional caption
            chat_id: Target chat
            parse_mode: Caption parse mode

        Returns:
            Message object or None
        """
        return self._request(
            "sendPhoto",
            chat_id=chat_id or self._default_chat_id,
            photo=photo,
            caption=caption,
            parse_mode=parse_mode,
        )

    def send_document(
        self,
        document: str,
        caption: str | None = None,
        chat_id: str | int | None = None,
        parse_mode: str | None = None,
    ) -> dict | None:
        """Send a document by URL.

        Args:
            document: Document URL or file_id
            caption: Optional caption
            chat_id: Target chat
            parse_mode: Caption parse mode

        Returns:
            Message object or None
        """
        return self._request(
            "sendDocument",
            chat_id=chat_id or self._default_chat_id,
            document=document,
            caption=caption,
            parse_mode=parse_mode,
        )

    def edit_message(
        self,
        message_id: int,
        text: str,
        chat_id: str | int | None = None,
        parse_mode: str | None = None,
    ) -> dict | None:
        """Edit a previously sent message.

        Args:
            message_id: ID of message to edit
            text: New message text
            chat_id: Chat containing the message
            parse_mode: Text parse mode

        Returns:
            Edited message object or None
        """
        return self._request(
            "editMessageText",
            chat_id=chat_id or self._default_chat_id,
            message_id=message_id,
            text=_truncate_message(text),
            parse_mode=parse_mode,
        )

    def delete_message(
        self,
        message_id: int,
        chat_id: str | int | None = None,
    ) -> bool:
        """Delete a message.

        Args:
            message_id: ID of message to delete
            chat_id: Chat containing the message

        Returns:
            True if deleted successfully
        """
        result = self._request(
            "deleteMessage",
            chat_id=chat_id or self._default_chat_id,
            message_id=message_id,
        )
        return result is True

    def pin_message(
        self,
        message_id: int,
        chat_id: str | int | None = None,
        silent: bool = False,
    ) -> bool:
        """Pin a message in a chat.

        Args:
            message_id: ID of message to pin
            chat_id: Chat containing the message
            silent: Pin without notification

        Returns:
            True if pinned successfully
        """
        result = self._request(
            "pinChatMessage",
            chat_id=chat_id or self._default_chat_id,
            message_id=message_id,
            disable_notification=silent,
        )
        return result is True

    def get_me(self) -> dict | None:
        """Get bot information.

        Returns:
            Bot user object or None
        """
        return self._request("getMe")

    def get_chat(self, chat_id: str | int | None = None) -> dict | None:
        """Get chat information.

        Args:
            chat_id: Chat to get info for

        Returns:
            Chat object or None
        """
        return self._request(
            "getChat",
            chat_id=chat_id or self._default_chat_id,
        )


class _LazyTelegram:
    """Lazy proxy for TelegramBot that initializes on first access.

    This defers TelegramBot creation until first use, ensuring environment
    variables from .env are loaded before reading TELEGRAM_BOT_TOKEN.
    """

    _instance: TelegramBot | None = None

    def _get_instance(self) -> TelegramBot:
        if self._instance is None:
            self._instance = TelegramBot()
        return self._instance

    def __getattr__(self, name: str) -> Any:
        return getattr(self._get_instance(), name)


# Global instance using environment variables
# Users can import and use directly: from brawny.telegram import telegram
telegram: TelegramBot = _LazyTelegram()  # type: ignore[assignment]


def get_telegram(
    token: str | None = None,
    chat_id: str | None = None,
) -> TelegramBot:
    """Get a Telegram bot instance.

    Use this to create a bot with custom configuration.
    For the default instance, just import `telegram` directly.

    Args:
        token: Bot token (defaults to env var)
        chat_id: Default chat ID (defaults to env var)

    Returns:
        TelegramBot instance
    """
    if token or chat_id:
        return TelegramBot(token=token, chat_id=chat_id)
    return telegram._get_instance()  # type: ignore[union-attr]
