# -*- coding: utf-8 -*-
"""
ابزارهای کمکی مشترک
========================
شامل یک مدیریت وضعیت (State Machine) ساده‌ی درون‌حافظه‌ای برای
مکالمات چند مرحله‌ای (مثل «آیدی کانال رو بفرست»، «مبلغ رو وارد کن» و ...)
و چند تابع فرمت‌دهی و بررسی عضویت.
"""

import html
import threading

import telebot

import database as db

# ---------------------------------------------------------------------------
# مدیریت وضعیت مکالمه (FSM ساده)
# ---------------------------------------------------------------------------
_states = {}
_states_lock = threading.RLock()


def set_state(user_id, state, data=None):
    with _states_lock:
        _states[user_id] = {"state": state, "data": data or {}}


def get_state(user_id):
    with _states_lock:
        return _states.get(user_id)


def clear_state(user_id):
    with _states_lock:
        _states.pop(user_id, None)


def update_state_data(user_id, **kwargs):
    with _states_lock:
        if user_id in _states:
            _states[user_id]["data"].update(kwargs)


# ---------------------------------------------------------------------------
# فرمت‌دهی
# ---------------------------------------------------------------------------
def fmt_num(n):
    """1234567 -> 1,234,567"""
    try:
        return f"{int(n):,}"
    except (TypeError, ValueError):
        return str(n)


def toman(n):
    return f"{fmt_num(n)} تومان"


def fmt_hms(seconds):
    """۳۶۶۵ ثانیه -> "1 ساعت و 1 دقیقه" برای نمایش شمارش‌معکوس پاداش روزانه."""
    seconds = int(seconds)
    hours, remainder = divmod(seconds, 3600)
    minutes = remainder // 60
    if hours > 0:
        return f"{hours} ساعت و {minutes} دقیقه"
    if minutes > 0:
        return f"{minutes} دقیقه"
    return "چند لحظه"


class _SafeDict(dict):
    def __missing__(self, key):
        return "{" + key + "}"


def safe_format(template, **kwargs):
    """
    مثل str.format ولی اگه ادمین یه placeholder رو از متن حذف کرده باشه یا
    فرمت خراب باشه، ارور نمیده و بدون کرش، بهترین خروجی ممکن رو برمیگردونه.
    """
    try:
        return template.format_map(_SafeDict(**kwargs))
    except Exception:
        return template


def render_text(key, **kwargs):
    """متن با کلید مشخص رو از دیتابیس (یا پیش‌فرض) میخونه و پر میکنه."""
    template = db.get_text(key)
    return safe_format(template, **kwargs)


def render_text_html(key, **kwargs):
    """
    مثل render_text ولی برای وقتی که میخوایم parse_mode='HTML' بفرستیم.
    متن قالب (که ادمین آزادانه می‌نویسدش) رو escape میکنه تا اگه یه‌وقت
    کاراکتر خاصی توش بود مشکلی پیش نیاد، ولی مقادیری که خودت از قبل به
    شکل HTML امن آماده کردی (مثل <code>...</code> برای شماره کارت) دست‌نخورده
    جایگزین میشن - چون escape فقط روی خودِ قالب انجام میشه، نه مقادیر ورودی.
    """
    template = db.get_text(key)
    escaped_template = html.escape(template)
    return safe_format(escaped_template, **kwargs)


def is_button(text, button_key):
    """چک میکنه آیا متن پیام دقیقا برچسب فعلیِ دکمه‌ی button_key هست یا نه."""
    btn = db.get_menu_button(button_key)
    return bool(btn) and bool(btn["enabled"]) and btn["label"] == text


def normalize_channel_id(text):
    """
    ورودی کاربر رو به فرمت قابل استفاده در API تبدیل میکنه.
    قبول میکنه: @username / https://t.me/username / username / -100xxxxxxxxxx
    """
    text = text.strip()
    if text.startswith("https://t.me/"):
        text = text.replace("https://t.me/", "")
    elif text.startswith("http://t.me/"):
        text = text.replace("http://t.me/", "")
    elif text.startswith("t.me/"):
        text = text.replace("t.me/", "")
    text = text.strip("/ ")
    if text.startswith("-100") or (text.lstrip("-").isdigit()):
        return text
    if not text.startswith("@"):
        text = "@" + text
    return text


def channel_link(channel_id, fallback_title=""):
    """لینک قابل کلیک برای یک کانال میسازه."""
    if isinstance(channel_id, str) and channel_id.startswith("@"):
        return f"https://t.me/{channel_id[1:]}"
    return f"tg://resolve?domain={fallback_title}" if fallback_title else "https://t.me"


def build_message_link(channel_id, message_id):
    """
    لینک مستقیم به یک پیام مشخص توی یک کانال میسازه (برای دکمه‌ی
    «مشاهده سفارش» که مستقیم می‌بره روی همون پست توی کانال لاگ).
    """
    if isinstance(channel_id, str) and channel_id.startswith("@"):
        return f"https://t.me/{channel_id[1:]}/{message_id}"
    numeric = str(channel_id).lstrip("-")
    if numeric.startswith("100"):
        numeric = numeric[3:]
    return f"https://t.me/c/{numeric}/{message_id}"


# ---------------------------------------------------------------------------
# بررسی عضویت در کانال
# ---------------------------------------------------------------------------
def is_member(bot: telebot.TeleBot, channel_id, user_id):
    """
    بررسی میکنه کاربر عضو کانال هست یا نه.
    ربات باید توی اون کانال ادمین باشه وگرنه ارور میده و False برمیگردونیم.
    """
    try:
        member = bot.get_chat_member(channel_id, user_id)
        return member.status in ("member", "administrator", "creator")
    except Exception:
        return False


def missing_force_channels(bot: telebot.TeleBot, user_id):
    """لیست کانال‌های اجباری که کاربر هنوز عضو نشده رو برمیگردونه."""
    missing = []
    for ch in db.list_force_channels():
        if not is_member(bot, ch["channel_id"], user_id):
            missing.append(ch)
    return missing
