# -*- coding: utf-8 -*-
"""
یک wrapper بسیار سبک روی Telegram Bot API با کتابخانه requests.
از کتابخانه‌ی سنگین python-telegram-bot استفاده نشده تا مصرف رم روی هاست کم بماند.
"""

import json
import re

import requests

from config import BOT_TOKEN

API_URL = f"https://api.telegram.org/bot{BOT_TOKEN}"


def _post(method, **kwargs):
    files = kwargs.pop("files", None)
    resp = requests.post(f"{API_URL}/{method}", data=kwargs, files=files, timeout=20)
    try:
        return resp.json()
    except Exception:
        return {"ok": False, "raw": resp.text}


# ---------------------------------------------------------------------------
# تبدیل خودکار ایموجی‌های معمولی به ایموجی پریمیوم در متن پیام‌ها و کپشن‌ها
# (برای همه‌ی پیام‌ها از جمله پیام‌هایی که به ادمین‌ها می‌رود).
# نگاشت «ایموجی معمولی -> آیدی ایموجی پریمیوم» را app.py با set_premium_map ثبت می‌کند.
# ---------------------------------------------------------------------------

_PREMIUM_MAP = {}
_PREMIUM_RE = None
_TG_EMOJI_TAG_RE = re.compile(r"(<tg-emoji\b[^>]*>.*?</tg-emoji>)", re.S)


def set_premium_map(mapping):
    global _PREMIUM_RE
    _PREMIUM_MAP.clear()
    _PREMIUM_MAP.update(mapping)
    if mapping:
        chars = "|".join(re.escape(c) for c in sorted(mapping, key=len, reverse=True))
        _PREMIUM_RE = re.compile(f"(?:{chars})\ufe0f?")
    else:
        _PREMIUM_RE = None


def _u16(s):
    return len(s.encode("utf-16-le")) // 2


def _premium_id(matched):
    return _PREMIUM_MAP[matched.replace("\ufe0f", "")]


def _premium_html(text):
    """در متن HTML، ایموجی‌های معمولی را با تگ tg-emoji جایگزین می‌کند (بدون دست‌زدن به تگ‌های tg-emoji موجود)."""
    def conv(piece):
        return _PREMIUM_RE.sub(
            lambda m: f'<tg-emoji emoji-id="{_premium_id(m.group(0))}">{m.group(0)}</tg-emoji>', piece
        )
    parts = _TG_EMOJI_TAG_RE.split(text)
    return "".join(p if i % 2 else conv(p) for i, p in enumerate(parts))


def _premium_entities(text, entities):
    """entity های custom_emoji را برای ایموجی‌های معمولی متن اضافه می‌کند و لیست جدید را برمی‌گرداند."""
    entities = list(entities or [])
    covered = {e["offset"] for e in entities if e.get("type") == "custom_emoji"}
    code_ranges = [(e["offset"], e["offset"] + e["length"]) for e in entities if e.get("type") in ("code", "pre")]
    new = []
    for m in _PREMIUM_RE.finditer(text):
        off = _u16(text[:m.start()])
        if off in covered or any(a <= off < b for a, b in code_ranges):
            continue
        new.append({
            "type": "custom_emoji",
            "offset": off,
            "length": _u16(m.group(0)),
            "custom_emoji_id": _premium_id(m.group(0)),
        })
    return sorted(entities + new, key=lambda e: e["offset"])


def _prepare_text(text, entities, parse_mode):
    if not _PREMIUM_RE or not text:
        return text, entities, parse_mode
    if entities:
        return text, _premium_entities(text, entities), parse_mode
    if parse_mode == "HTML":
        return _premium_html(text), entities, parse_mode
    if not parse_mode:
        return text, (_premium_entities(text, []) or None), parse_mode
    return text, entities, parse_mode


CAPTION_LIMIT = 1000  # سقف تلگرام ۱۰۲۴ است؛ کمی حاشیه برای ایموجی‌ها (۲ واحد UTF-16)


def _caption_kwargs(caption):
    if not caption:
        return {}
    if len(caption) > CAPTION_LIMIT:
        caption = caption[:CAPTION_LIMIT - 10] + "…"
    if _PREMIUM_RE:
        ents = _premium_entities(caption, [])
        if ents:
            return {"caption": caption, "caption_entities": json.dumps(ents)}
    return {"caption": caption}


def send_message(chat_id, text, reply_markup=None, parse_mode="HTML", entities=None):
    text, entities, parse_mode = _prepare_text(text, entities, parse_mode)
    kwargs = {"chat_id": chat_id, "text": text}
    if entities:
        kwargs["entities"] = json.dumps(entities)  # entities و parse_mode با هم قابل استفاده نیستند
    elif parse_mode:
        kwargs["parse_mode"] = parse_mode
    if reply_markup:
        kwargs["reply_markup"] = json.dumps(reply_markup)
    return _post("sendMessage", **kwargs)


def answer_callback_query(callback_query_id, text=None, show_alert=False):
    # تلگرام روی form-data مقدار بولین را باید به صورت "true"/"false" (حروف کوچک) بگیرد،
    # ولی پایتون به‌صورت پیش‌فرض True/False می‌سازد که ممکن است درست تفسیر نشود.
    kwargs = {
        "callback_query_id": callback_query_id,
        "show_alert": "true" if show_alert else "false",
    }
    if text:
        kwargs["text"] = text
    return _post("answerCallbackQuery", **kwargs)


def edit_message_text(chat_id, message_id, text, reply_markup=None, parse_mode="HTML", entities=None):
    text, entities, parse_mode = _prepare_text(text, entities, parse_mode)
    kwargs = {"chat_id": chat_id, "message_id": message_id, "text": text}
    if entities:
        kwargs["entities"] = json.dumps(entities)
    elif parse_mode:
        kwargs["parse_mode"] = parse_mode
    if reply_markup:
        kwargs["reply_markup"] = json.dumps(reply_markup)
    return _post("editMessageText", **kwargs)


def edit_message_caption(chat_id, message_id, caption, entities=None, reply_markup=None):
    """ویرایش کپشن پیام‌های عکس‌دار (مثلاً پیام سفارش همراه رسید برای ادمین‌ها)."""
    kwargs = {"chat_id": chat_id, "message_id": message_id, "caption": caption}
    if entities:
        kwargs["caption_entities"] = json.dumps(entities)
    if reply_markup is not None:
        kwargs["reply_markup"] = json.dumps(reply_markup)
    return _post("editMessageCaption", **kwargs)


def edit_message_reply_markup(chat_id, message_id, reply_markup=None):
    """کیبورد اینلاین یک پیام را عوض می‌کند؛ بدون reply_markup دکمه‌ها کلاً برداشته می‌شوند
    (برای پیام متنی، عکس و فایل کار می‌کند)."""
    markup = reply_markup if reply_markup else {"inline_keyboard": []}
    return _post("editMessageReplyMarkup", chat_id=chat_id, message_id=message_id,
                 reply_markup=json.dumps(markup))


def forward_message(chat_id, from_chat_id, message_id):
    return _post("forwardMessage", chat_id=chat_id, from_chat_id=from_chat_id, message_id=message_id)


def copy_message(chat_id, from_chat_id, message_id):
    """مثل forward_message است، با این فرق که پیام بدون برچسب «Forwarded from» ارسال می‌شود
    و برای هر نوع محتوایی (متن، عکس، فایل، ویدیو و ...) کار می‌کند. برای پیام همگانی استفاده می‌شود."""
    return _post("copyMessage", chat_id=chat_id, from_chat_id=from_chat_id, message_id=message_id)


def send_document_by_file_id(chat_id, file_id, caption=None, reply_markup=None):
    kwargs = {"chat_id": chat_id, "document": file_id}
    kwargs.update(_caption_kwargs(caption))
    if reply_markup:
        kwargs["reply_markup"] = json.dumps(reply_markup)
    return _post("sendDocument", **kwargs)


def send_photo_by_file_id(chat_id, file_id, caption=None, reply_markup=None):
    kwargs = {"chat_id": chat_id, "photo": file_id}
    kwargs.update(_caption_kwargs(caption))
    if reply_markup:
        kwargs["reply_markup"] = json.dumps(reply_markup)
    return _post("sendPhoto", **kwargs)


_MEDIA_METHODS = {
    "photo": ("sendPhoto", "photo"),
    "video": ("sendVideo", "video"),
    "audio": ("sendAudio", "audio"),
    "voice": ("sendVoice", "voice"),
    "document": ("sendDocument", "document"),
}


def send_media_by_file_id(chat_id, kind, file_id, caption=None, reply_markup=None, caption_entities=None):
    """ارسال عکس/ویدیو/آهنگ/ویس/فایل با file_id (kind یکی از photo, video, audio, voice, document).
    caption_entities (اختیاری): entity های آماده (بولد، ایموجی پریمیوم، ...) برای کپشن."""
    method, field = _MEDIA_METHODS[kind]
    kwargs = {"chat_id": chat_id, field: file_id}
    if caption and caption_entities:
        kwargs["caption"] = caption
        kwargs["caption_entities"] = json.dumps(caption_entities)
    else:
        kwargs.update(_caption_kwargs(caption))
    if reply_markup:
        kwargs["reply_markup"] = json.dumps(reply_markup)
    return _post(method, **kwargs)


def delete_message(chat_id, message_id):
    return _post("deleteMessage", chat_id=chat_id, message_id=message_id)


def set_message_reaction(chat_id, message_id, emoji="👍"):
    """روی پیام یک واکنش (ریاکشن) می‌گذارد؛ به‌جای پیام «ارسال شد» استفاده می‌شود."""
    return _post(
        "setMessageReaction", chat_id=chat_id, message_id=message_id,
        reaction=json.dumps([{"type": "emoji", "emoji": emoji}]),
    )


def send_local_document(chat_id, file_path, caption=None):
    with open(file_path, "rb") as f:
        files = {"document": f}
        kwargs = {"chat_id": chat_id}
        if caption:
            kwargs["caption"] = caption
        return _post("sendDocument", files=files, **kwargs)


def set_webhook(url, secret_token=None):
    """secret_token: اگر داده شود، تلگرام آن را در هدر X-Telegram-Bot-Api-Secret-Token
    همراه هر درخواست وبهوک می‌فرستد تا سرور بتواند درخواست‌های جعلی را رد کند."""
    kwargs = {"url": url}
    if secret_token:
        kwargs["secret_token"] = secret_token
    return _post("setWebhook", **kwargs)


def get_me():
    return _post("getMe")


def set_my_commands(commands, chat_id=None):
    """
    commands: لیستی از دیکشنری‌های {"command": "...", "description": "..."}
    chat_id: اگر داده شود، این لیست فقط برای همان چت (مثلاً ادمین) اعمال می‌شود؛
             در غیر این صورت لیست پیش‌فرض برای همه‌ی کاربران است.
    """
    kwargs = {"commands": json.dumps(commands, ensure_ascii=False)}
    if chat_id is not None:
        kwargs["scope"] = json.dumps({"type": "chat", "chat_id": chat_id})
    return _post("setMyCommands", **kwargs)


def delete_webhook():
    return _post("deleteWebhook")


def get_file_path(file_id):
    resp = requests.get(f"{API_URL}/getFile", params={"file_id": file_id}, timeout=20).json()
    if resp.get("ok"):
        return resp["result"]["file_path"]
    return None


def download_file(file_id, dest_path):
    file_path = get_file_path(file_id)
    if not file_path:
        return False
    url = f"https://api.telegram.org/file/bot{BOT_TOKEN}/{file_path}"
    r = requests.get(url, timeout=30)
    with open(dest_path, "wb") as f:
        f.write(r.content)
    return True
