"""
Thin client for the Telegram Bot HTTP API.

Each outgoing call retries on failure with the same policy the original system
used (up to HTTP_MAX_TRIES attempts, HTTP_RETRY_WAIT_SECONDS apart).
"""

import time

import requests

from .. import config


class TelegramAPI:
    def __init__(self, token: str = None, base: str = None):
        self.token = token or config.BOT_TOKEN
        self.base = (base or config.TELEGRAM_API_BASE).rstrip("/")

    def _url(self, method: str) -> str:
        return f"{self.base}/bot{self.token}/{method}"

    def _post(self, method: str, payload: dict, retry: bool = True, timeout: int = 30) -> dict:
        url = self._url(method)
        tries = config.HTTP_MAX_TRIES if retry else 1
        last_error = None
        for attempt in range(1, tries + 1):
            try:
                resp = requests.post(url, json=payload, timeout=timeout)
                resp.raise_for_status()
                return resp.json()
            except Exception as exc:  # network/HTTP error
                last_error = exc
                if attempt < tries:
                    time.sleep(config.HTTP_RETRY_WAIT_SECONDS)
        raise last_error

    # --- API methods -----------------------------------------------------------

    def send_message(
        self,
        chat_id,
        text: str,
        reply_markup: dict = None,
        reply_to_message_id: int = None,
        parse_mode: str = None,
        retry: bool = True,
    ) -> dict:
        payload = {"chat_id": str(chat_id), "text": text}
        if reply_markup is not None:
            payload["reply_markup"] = reply_markup
        if reply_to_message_id is not None:
            payload["reply_to_message_id"] = reply_to_message_id
        if parse_mode is not None:
            payload["parse_mode"] = parse_mode
        return self._post("sendMessage", payload, retry=retry)

    def get_chat_member(self, chat_id, user_id) -> dict:
        """
        Returns the membership record. Errors are surfaced to the caller so the
        decision logic can treat a failed lookup as "not a member".
        """
        payload = {"chat_id": chat_id, "user_id": user_id}
        return self._post("getChatMember", payload)

    def set_webhook(self, url: str) -> dict:
        return self._post("setWebhook", {"url": url})

    def delete_webhook(self, drop_pending: bool = False) -> dict:
        return self._post("deleteWebhook", {"drop_pending_updates": drop_pending})

    def get_updates(self, offset: int = None, timeout: int = 30) -> list:
        """
        Long-poll for new updates (used when running without a public webhook).
        Returns the list of update objects.
        """
        payload = {"timeout": timeout}
        if offset is not None:
            payload["offset"] = offset
        # Allow the long-poll to wait server-side; give the HTTP read a little
        # more time than the server-side timeout, and never retry-loop a poll.
        data = self._post("getUpdates", payload, retry=False, timeout=timeout + 10)
        return data.get("result", []) if isinstance(data, dict) else []
