"""Telegram Bot API helpers for OpenClaw Bot.

Route modules should keep only request handling and command dispatch. Telegram
delivery, Markdown fallback, and file upload glue live here so they can be
reused and tested without importing the 5k-line Blueprint.
"""

from __future__ import annotations

import os
import re

import requests

from services.logger_manager import SystemLogger


BOT_TOKEN = os.getenv("OPENCLAW_BOT_TOKEN") or os.getenv("TELEGRAM_BOT_TOKEN", "")
BOT_API_URL = f"https://api.telegram.org/bot{BOT_TOKEN}"
sys_log = SystemLogger("OpenClawBot").get_logger()


def _tg(method: str, payload: dict):
    try:
        response = requests.post(f"{BOT_API_URL}/{method}", json=payload, timeout=10)
        if not response.ok:
            sys_log.warning(f"[OpenClawBot] {method} failed: {response.text[:200]}")
        return response.json()
    except Exception as exc:
        sys_log.error(f"[OpenClawBot] {method} error: {exc}")
        return {}


def _strip_markdown(text: str) -> str:
    """移除 Telegram Markdown v1 格式符號，轉為純文字（send fallback 用）"""
    text = re.sub(r"\*([^*]+)\*", r"\1", text)
    text = re.sub(r"_([^_]+)_", r"\1", text)
    text = re.sub(r"`([^`]+)`", r"\1", text)
    text = re.sub(r"\[([^\]]+)\]\([^)]+\)", r"\1", text)
    return text


def send_message(chat_id, text, reply_to=None, keyboard=None, parse_mode="Markdown"):
    """送出 Telegram 訊息。Markdown 解析失敗時自動降級為純文字重送。"""

    def _build_payload(txt, pm):
        payload = {"chat_id": chat_id, "text": txt, "disable_web_page_preview": True}
        if pm:
            payload["parse_mode"] = pm
        if reply_to:
            payload["reply_to_message_id"] = reply_to
        if keyboard:
            payload["reply_markup"] = {"inline_keyboard": keyboard}
        return payload

    result = _tg("sendMessage", _build_payload(text, parse_mode))
    if result.get("ok"):
        return result

    if parse_mode and not result.get("ok"):
        err = result.get("description", "")
        if "parse" in err.lower() or "entity" in err.lower() or "can't find" in err.lower():
            sys_log.warning("[OpenClawBot] Markdown parse failed, retrying as plain text")
            result2 = _tg("sendMessage", _build_payload(_strip_markdown(text), None))
            if result2.get("ok"):
                return result2

    if len(text) > 4000:
        sys_log.warning(f"[OpenClawBot] Message too long ({len(text)}), truncating")
        truncated = _strip_markdown(text[:3900]) + "\n...(訊息過長已截斷)"
        return _tg("sendMessage", _build_payload(truncated, None))

    return result


def _build_edit_payload(chat_id, message_id, text, pm, keyboard):
    payload = {"chat_id": chat_id, "message_id": message_id, "text": text}
    if pm:
        payload["parse_mode"] = pm
    if keyboard:
        payload["reply_markup"] = {"inline_keyboard": keyboard}
    return payload


def edit_message_text(chat_id, message_id, text, keyboard=None, parse_mode="Markdown"):
    """編輯既有訊息。Markdown 失敗時自動降級為純文字。"""
    result = _tg(
        "editMessageText",
        _build_edit_payload(chat_id, message_id, text, parse_mode, keyboard),
    )
    if result.get("ok"):
        return result

    if parse_mode and not result.get("ok"):
        err = result.get("description", "")
        if "parse" in err.lower() or "entity" in err.lower() or "can't find" in err.lower():
            sys_log.warning("[OpenClawBot] editMessageText Markdown failed, retrying plain text")
            result2 = _tg(
                "editMessageText",
                _build_edit_payload(chat_id, message_id, _strip_markdown(text), None, keyboard),
            )
            if result2.get("ok"):
                return result2

    if len(text) > 4000:
        sys_log.warning(f"[OpenClawBot] Message too long ({len(text)}), truncating")
        truncated = _strip_markdown(text[:3900]) + "\n...(訊息過長已截斷)"
        return _tg("editMessageText", _build_edit_payload(chat_id, message_id, truncated, None, keyboard))

    return result


def answer_callback(cq_id, text=""):
    return _tg("answerCallbackQuery", {"callback_query_id": cq_id, "text": text})


def send_typing(chat_id):
    try:
        requests.post(
            f"{BOT_API_URL}/sendChatAction",
            json={"chat_id": chat_id, "action": "typing"},
            timeout=5,
        )
    except Exception as exc:
        sys_log.debug(f"[OpenClawBot] sendChatAction skipped: {exc}")


def send_photo(chat_id, file_path, caption="", reply_to=None):
    """透過 Telegram Bot API 傳送圖片"""
    try:
        with open(file_path, "rb") as handle:
            data = {"chat_id": chat_id}
            if caption:
                data["caption"] = caption
            if reply_to:
                data["reply_to_message_id"] = reply_to
            response = requests.post(
                f"{BOT_API_URL}/sendPhoto",
                data=data,
                files={"photo": handle},
                timeout=30,
            )
        if not response.ok:
            sys_log.warning(f"[OpenClawBot] sendPhoto failed: {response.text[:200]}")
        return response.json()
    except Exception as exc:
        sys_log.error(f"[OpenClawBot] sendPhoto error: {exc}")
        return {}


def send_document(chat_id, file_path, caption="", reply_to=None):
    """透過 Telegram Bot API 傳送文件"""
    try:
        with open(file_path, "rb") as handle:
            data = {"chat_id": chat_id}
            if caption:
                data["caption"] = caption
            if reply_to:
                data["reply_to_message_id"] = reply_to
            response = requests.post(
                f"{BOT_API_URL}/sendDocument",
                data=data,
                files={"document": handle},
                timeout=30,
            )
        if not response.ok:
            sys_log.warning(f"[OpenClawBot] sendDocument failed: {response.text[:200]}")
        return response.json()
    except Exception as exc:
        sys_log.error(f"[OpenClawBot] sendDocument error: {exc}")
        return {}
