import math
# کیف پول، شارژ، کد هدیه، زیرمجموعه

import os
import time
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup, ReplyKeyboardMarkup, KeyboardButton, WebAppInfo
from telegram.ext import ContextTypes, ConversationHandler
from config import ADMIN_ID, BOT_TOKEN
from db_users import (
    get_bot_user, upsert_bot_user, user_vars, render_template, log_activity,
    create_charge, get_charge, set_charge_receipt, list_cards, list_payment_methods,
    redeem_gift, count_referrals,
)
from database import get_setting_sync, payment_method_button

WAITING_CHARGE_AMOUNT = 10
WAITING_GIFT_CODE = 11
WAITING_RECEIPT = 12

# کش کوتاه منوی اصلی؛ تغییرات پنل حداکثر چند ثانیه بعد اعمال می‌شوند.
_MAIN_KEYBOARD_CACHE = {}


def invalidate_main_keyboard_cache():
    """پاک‌کردن کش منوی اصلی بعد از تغییر چیدمان/تنظیمات."""
    _MAIN_KEYBOARD_CACHE.clear()
_MAIN_KEYBOARD_CACHE_TTL = 3.0

def main_user_keyboard(is_admin: bool = False, force_inline: bool = None):
    """
    منوی اصلی.
    - به صورت پیش‌فرض ReplyKeyboard (دکمه‌ای) همیشه فعال است.
    - اگر inline_main_menu=1 باشد، InlineKeyboard (شیشه‌ای) برمی‌گردد.
    - force_inline=True/False برای اجبار یکی از دو حالت.
    رنگ و ایموجی پریمیوم فقط روی حالت شیشه‌ای اعمال می‌شود.
    """
    from database import get_setting_sync
    from db_extras import (
        get_menu_buttons, build_menu_rows, COLOR_TO_STYLE,
        extract_premium_from_label, strip_premium_codes,
    )

    if force_inline is None:
        use_inline = get_setting_sync("inline_main_menu", "0") == "1"
    else:
        use_inline = bool(force_inline)

    cache_key = (bool(is_admin), bool(use_inline))
    now = time.monotonic()
    cached = _MAIN_KEYBOARD_CACHE.get(cache_key)
    if cached and now - cached[0] < _MAIN_KEYBOARD_CACHE_TTL:
        return cached[1]

    # از اینجا به بعد فقط یک‌بار در هر چند ثانیه تنظیمات سنگین منو خوانده می‌شوند.
    menu_rows = build_menu_rows(get_menu_buttons())
    miniapp_url = (get_setting_sync('miniapp_url', '') or os.getenv('MINIAPP_URL', '') or '').strip()
    if miniapp_url and not miniapp_url.endswith('/'):
        miniapp_url = miniapp_url + '/'
    miniapp_btn_enabled = get_setting_sync('miniapp_btn_enabled', '1') != '0'
    miniapp_btn_label = (get_setting_sync('miniapp_btn_label', '') or '✦ ورود به اپلیکیشن').strip() or '✦ ورود به اپلیکیشن'

    if use_inline:
        rows = []
        if miniapp_url and miniapp_btn_enabled:
            rows.append([InlineKeyboardButton(miniapp_btn_label[:64], web_app=WebAppInfo(url=miniapp_url))])
        for group in menu_rows:
            row = []
            for item in group:
                raw_label = (item.get("label") or item.get("key") or "—").split("\n")[0]
                clean, eid = extract_premium_from_label(raw_label)
                clean = (clean or "•")[:40]
                style = COLOR_TO_STYLE.get((item.get("color") or "none").lower())
                kwargs = {"text": clean, "callback_data": item.get("callback") or "menu_home"}
                if style:
                    kwargs["style"] = style
                if eid:
                    kwargs["icon_custom_emoji_id"] = eid
                try:
                    row.append(InlineKeyboardButton(**kwargs))
                except TypeError:
                    row.append(InlineKeyboardButton(clean, callback_data=kwargs["callback_data"]))
            if row:
                rows.append(row)
        if is_admin:
            rows.append([InlineKeyboardButton("⚙️ مدیریت", callback_data="menu_admin")])
        markup = InlineKeyboardMarkup(rows)
        _MAIN_KEYBOARD_CACHE[cache_key] = (now, markup)
        return markup

    # Reply keyboard — رنگ واقعی با style (Bot API 9.4+ / PTB 22.7+)
    # primary=آبی · success=سبز · danger=قرمز
    rows = []
    if miniapp_url and miniapp_btn_enabled:
        try:
            rows.append([KeyboardButton(miniapp_btn_label[:64], web_app=WebAppInfo(url=miniapp_url))])
        except TypeError:
            pass
    for group in menu_rows:
        row = []
        for item in group:
            raw_label = (item.get("label") or item.get("key") or "—").split("\n")[0]
            clean, eid = extract_premium_from_label(raw_label)
            clean = (clean or "•")[:40]
            style = COLOR_TO_STYLE.get((item.get("color") or "none").lower())
            kwargs = {"text": clean}
            if style:
                kwargs["style"] = style
            if eid:
                kwargs["icon_custom_emoji_id"] = eid
            try:
                row.append(KeyboardButton(**kwargs))
            except TypeError:
                row.append(KeyboardButton(clean))
        if row:
            rows.append(row)
    if is_admin:
        try:
            rows.append([KeyboardButton("⚙️ مدیریت", style="primary")])
        except TypeError:
            rows.append([KeyboardButton("⚙️ مدیریت")])
    markup = ReplyKeyboardMarkup(rows, resize_keyboard=True)
    _MAIN_KEYBOARD_CACHE[cache_key] = (now, markup)
    return markup


def main_user_keyboards(is_admin: bool = False):
    """هر دو کیبورد را برمی‌گرداند: (reply, inline یا None)"""
    from database import get_setting_sync
    reply = main_user_keyboard(is_admin=is_admin, force_inline=False)
    inline = None
    if get_setting_sync("inline_main_menu", "0") == "1":
        inline = main_user_keyboard(is_admin=is_admin, force_inline=True)
    return reply, inline




def wallet_keyboard():
    return InlineKeyboardMarkup([
        [InlineKeyboardButton("💳 شارژ حساب", callback_data="wallet_charge")],
        [InlineKeyboardButton("🎁 کد هدیه", callback_data="wallet_gift")],
        [InlineKeyboardButton("👥 زیرمجموعه", callback_data="wallet_refs")],
        [InlineKeyboardButton("🏠 منوی اصلی", callback_data="menu_home")],
    ])

def payment_methods_keyboard(charge_id: int):
    from database import get_setting_sync
    methods = list_payment_methods(active_only=True)
    rows = []
    for m in methods:
        key = m.get("method_key")
        if key == "variza":
            try:
                from services.variza import configured, is_enabled
                if not (is_enabled() and configured()):
                    continue
            except Exception:
                continue
        if key == "stars":
            if get_setting_sync("stars_enabled", "0") != "1":
                continue
        rows.append([payment_method_button(m, f"pay_{m['method_key']}_{charge_id}")])
    rows.append([InlineKeyboardButton("❌ انصراف", callback_data="wallet_cancel")])
    rows.append([InlineKeyboardButton("🏠 منوی اصلی", callback_data="menu_home")])
    return InlineKeyboardMarkup(rows)

async def _bot_username(context: ContextTypes.DEFAULT_TYPE) -> str:
    try:
        me = await context.bot.get_me()
        return me.username or ""
    except Exception:
        return ""

async def show_wallet(update: Update, context: ContextTypes.DEFAULT_TYPE):
    user = update.effective_user
    bu = get_bot_user(user.id) or upsert_bot_user(user)
    uname = await _bot_username(context)
    text = render_template("wallet_main", user_vars(bu, uname))
    if update.message:
        await update.message.reply_text(text, reply_markup=wallet_keyboard(), parse_mode="HTML")
    elif update.callback_query:
        await update.callback_query.edit_message_text(text, reply_markup=wallet_keyboard(), parse_mode="HTML")
    pass  # navigation — not stored as activity

async def wallet_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
    q = update.callback_query
    await q.answer()
    data = q.data
    user = update.effective_user
    bu = get_bot_user(user.id)
    if not bu:
        bu = upsert_bot_user(user)
    uname = await _bot_username(context)

    if data == "wallet_cancel":
        await show_wallet(update, context)
        return ConversationHandler.END

    if data == "wallet_charge":
        vars_ = user_vars(bu, uname)
        text = render_template("wallet_charge", vars_)
        await q.edit_message_text(text, reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("🏠 منوی اصلی", callback_data="menu_home")]]), parse_mode="HTML")
        return WAITING_CHARGE_AMOUNT

    if data == "wallet_gift":
        text = render_template("wallet_gift", user_vars(bu, uname))
        await q.edit_message_text(text, reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("🏠 منوی اصلی", callback_data="menu_home")]]), parse_mode="HTML")
        return WAITING_GIFT_CODE

    if data == "wallet_refs":
        text = render_template("wallet_referrals", user_vars(bu, uname))
        await q.edit_message_text(text, reply_markup=wallet_keyboard(), parse_mode="HTML")
        return ConversationHandler.END

    if data.startswith("pay_variza_"):
        charge_id = int(data.split("_")[-1])
        ch = get_charge(charge_id)
        if not ch or int(ch["telegram_id"]) != user.id:
            await q.edit_message_text("فاکتور نامعتبر است.")
            return ConversationHandler.END
        try:
            from services.variza import create_payment_link, save_charge_link
            data_v = create_payment_link(int(ch["amount"]), "charge", charge_id, f"شارژ کیف پول #{charge_id}")
            save_charge_link(charge_id, data_v)
            kb = InlineKeyboardMarkup([[InlineKeyboardButton("💳 پرداخت با واریزا", url=data_v["pay_url"])],
                                       [InlineKeyboardButton("❌ انصراف", callback_data="wallet_cancel")],
                                       [InlineKeyboardButton("🏠 منوی اصلی", callback_data="menu_home")]])
            await q.edit_message_text(
                f"🧾 فاکتور شارژ #{charge_id}\n\n"
                f"مبلغ درخواستی: <b>{int(ch['amount']):,}</b> تومان\n\n"
                "با زدن دکمه زیر وارد صفحه واریزا شوید. پس از پرداخت، تایید به‌صورت خودکار انجام می‌شود و نیازی به ارسال رسید نیست.\n\n"
                "⚠️ مبلغ نهایی ممکن است برای تطبیق بانکی کمی متفاوت نمایش داده شود؛ پرداخت با شناسه همین فاکتور تطبیق می‌شود.",
                reply_markup=kb, parse_mode="HTML")
        except Exception as e:
            await q.edit_message_text(f"❌ ساخت لینک واریزا ناموفق بود.\n{str(e)[:250]}", reply_markup=payment_methods_keyboard(charge_id))
        return ConversationHandler.END

    if data.startswith("pay_card_"):
        if get_setting_sync("payment_method_card_enabled", "1") == "0":
            await q.edit_message_text("❌ پرداخت کارت‌به‌کارت در حال حاضر خاموش است.", reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("🏠 منوی اصلی", callback_data="menu_home")]]))
            return ConversationHandler.END
        charge_id = int(data.split("_")[-1])
        ch = get_charge(charge_id)
        if not ch or ch["telegram_id"] != user.id:
            await q.edit_message_text("فاکتور نامعتبر است.")
            return ConversationHandler.END
        cards = list_cards(active_only=True)
        if not cards:
            await q.edit_message_text("در حال حاضر کارتی تعریف نشده. با پشتیبانی تماس بگیرید.")
            return ConversationHandler.END
        card = cards[0]
        # ذخیره card_id
        from database import get_sync_connection
        conn = get_sync_connection()
        try:
            with conn.cursor() as cur:
                cur.execute("UPDATE charge_requests SET card_id=%s, method_key='card', status='waiting_receipt' WHERE id=%s", (card["id"], charge_id))
                conn.commit()
        finally:
            conn.close()
        vars_ = user_vars(bu, uname)
        vars_["amount"] = f"{int(ch['amount']):,}"
        vars_["invoice_id"] = charge_id
        vars_["card_number"] = card["card_number"]
        vars_["card_owner"] = card["owner_name"]
        text = render_template("charge_card_info", vars_)
        card_num = str(card["card_number"]).replace(" ", "").replace("-", "")
        try:
            from telegram import CopyTextButton
            copy_btn = InlineKeyboardButton("📋 کپی شماره کارت", copy_text=CopyTextButton(text=card_num))
        except Exception:
            copy_btn = InlineKeyboardButton("📋 کپی شماره کارت", callback_data=f"copy_card_{card['id']}")
        kb = InlineKeyboardMarkup([
            [copy_btn],
            [InlineKeyboardButton("❌ انصراف", callback_data="wallet_cancel")],
            [InlineKeyboardButton("🏠 منوی اصلی", callback_data="menu_home")],
        ])
        await q.edit_message_text(text, reply_markup=kb, parse_mode="HTML")
        context.user_data["waiting_receipt_charge_id"] = charge_id
        return WAITING_RECEIPT

    if data.startswith("pay_stars_"):
        from database import get_setting_sync
        if get_setting_sync("stars_enabled", "0") != "1":
            await q.edit_message_text("پرداخت با استارز غیرفعال است.", reply_markup=wallet_keyboard())
            return ConversationHandler.END
        charge_id = int(data.split("_")[-1])
        ch = get_charge(charge_id)
        if not ch or int(ch["telegram_id"]) != user.id:
            await q.edit_message_text("فاکتور نامعتبر است.")
            return ConversationHandler.END
        amount = int(ch.get("amount") or 0)
        try:
            rate = float(get_setting_sync("stars_rate", "1000") or 1000)
        except Exception:
            rate = 1000.0
        if rate <= 0:
            rate = 1000.0
        stars_amount = max(1, int(math.ceil(amount / rate)))
        title = get_setting_sync("stars_payment_title", "⭐ شارژ با استارز") or "⭐ شارژ با استارز"
        try:
            from telegram import LabeledPrice
            from database import get_sync_connection
            conn = get_sync_connection()
            try:
                with conn.cursor() as cur:
                    cur.execute(
                        "UPDATE charge_requests SET method_key='stars', status='pending_payment' WHERE id=%s",
                        (charge_id,),
                    )
                    conn.commit()
            finally:
                conn.close()
            await context.bot.send_invoice(
                chat_id=user.id,
                title=title[:32],
                description=f"شارژ کیف پول #{charge_id} — {amount:,} تومان",
                payload=f"charge_stars_{charge_id}",
                provider_token="",
                currency="XTR",
                prices=[LabeledPrice(label=title[:32], amount=stars_amount)],
            )
            await q.edit_message_text(
                f"⭐ فاکتور استارز ارسال شد.\n"
                f"مبلغ: <b>{amount:,}</b> تومان ≈ <b>{stars_amount}</b> استار\n"
                f"نرخ: هر استار ≈ {int(rate):,} تومان\n\n"
                "پس از پرداخت، موجودی به‌صورت خودکار اضافه می‌شود.",
                parse_mode="HTML",
                reply_markup=InlineKeyboardMarkup([
                    [InlineKeyboardButton("🏠 منوی اصلی", callback_data="menu_home")],
                ]),
            )
        except Exception as e:
            await q.edit_message_text(
                f"❌ خطا در ساخت فاکتور استارز:\n{str(e)[:250]}",
                reply_markup=payment_methods_keyboard(charge_id),
            )
        return ConversationHandler.END

    return ConversationHandler.END

async def receive_charge_amount(update: Update, context: ContextTypes.DEFAULT_TYPE):
    user = update.effective_user
    text = (update.message.text or "").replace(",", "").replace("،", "").strip()
    try:
        amount = int(text)
    except ValueError:
        await update.message.reply_text("مبلغ را به صورت عدد وارد کنید:")
        return WAITING_CHARGE_AMOUNT
    min_c = int(get_setting_sync("min_charge", "10000") or 10000)
    max_c = int(get_setting_sync("max_charge", "50000000") or 50000000)
    if amount < min_c or amount > max_c:
        await update.message.reply_text(f"مبلغ باید بین {min_c:,} و {max_c:,} تومان باشد:")
        return WAITING_CHARGE_AMOUNT
    charge_id = create_charge(user.id, amount, method_key="card")
    bu = get_bot_user(user.id)
    uname = await _bot_username(context)
    vars_ = user_vars(bu, uname)
    vars_["amount"] = f"{amount:,}"
    vars_["invoice_id"] = charge_id
    msg = render_template("charge_invoice", vars_)
    await update.message.reply_text(msg, reply_markup=payment_methods_keyboard(charge_id))
    log_activity(user.id, "charge_create", str(amount))
    return ConversationHandler.END

async def receive_gift_code(update: Update, context: ContextTypes.DEFAULT_TYPE):
    user = update.effective_user
    code = (update.message.text or "").strip()
    ok, msg, amount = redeem_gift(user.id, code)
    if ok:
        bu = get_bot_user(user.id)
        await update.message.reply_text(
            f"✅ {msg}\nمبلغ: {amount:,} تومان\nموجودی: {int(bu['balance']):,} تومان",
            reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("🏠 منوی اصلی", callback_data="menu_home")]]),
        )
    else:
        await update.message.reply_text(
            f"❌ {msg}",
            reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("🏠 منوی اصلی", callback_data="menu_home")]]),
        )
    return ConversationHandler.END

async def receive_receipt(update: Update, context: ContextTypes.DEFAULT_TYPE):
    user = update.effective_user
    charge_id = context.user_data.get("waiting_receipt_charge_id")
    if not charge_id:
        return ConversationHandler.END
    file_id = None
    if update.message.photo:
        file_id = update.message.photo[-1].file_id
    elif update.message.document:
        file_id = update.message.document.file_id
    else:
        await update.message.reply_text("لطفاً تصویر رسید را ارسال کنید.")
        return WAITING_RECEIPT
    set_charge_receipt(charge_id, file_id)
    bu = get_bot_user(user.id)
    uname = await _bot_username(context)
    vars_ = user_vars(bu, uname)
    vars_["invoice_id"] = charge_id
    vars_["amount"] = f"{int(get_charge(charge_id)['amount']):,}"
    await update.message.reply_text(
        render_template("charge_waiting", vars_),
        reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("🏠 منوی اصلی", callback_data="menu_home")]]),
    )
    # اطلاع به ادمین — همراه با نام، یوزرنیم و شماره
    display_name = " ".join(filter(None, [user.first_name, user.last_name])) or (bu or {}).get("first_name") or "—"
    username_str = f"@{user.username}" if user.username else ((bu or {}).get("username") and f"@{(bu or {}).get('username')}") or "—"
    phone_str = (bu or {}).get("phone") or "—"
    try:
        await context.bot.send_message(
            ADMIN_ID,
            (
                f"🧾 رسید جدید\n"
                f"کاربر: <code>{user.id}</code>\n"
                f"نام: {display_name}\n"
                f"یوزرنیم: {username_str}\n"
                f"شماره: {phone_str}\n"
                f"فاکتور: #{charge_id}\n"
                f"مبلغ: {vars_['amount']}"
            ),
            parse_mode="HTML",
            reply_markup=InlineKeyboardMarkup([
                [
                    InlineKeyboardButton("✅ تایید", callback_data=f"adm_ch_ok_{charge_id}"),
                    InlineKeyboardButton("❌ رد", callback_data=f"adm_ch_no_{charge_id}"),
                ],
                [
                    InlineKeyboardButton("💰 شارژ دستی", callback_data=f"adm_ch_manual_{charge_id}"),
                ],
            ]),
        )
        await context.bot.send_photo(ADMIN_ID, file_id, caption=f"رسید #{charge_id}")
    except Exception as e:
        print(f"notify admin: {e}")
    log_activity(user.id, "charge_receipt", str(charge_id))
    context.user_data.pop("waiting_receipt_charge_id", None)
    return ConversationHandler.END
