import time
import json
import sqlite3
import traceback
from datetime import datetime, date, timedelta

import requests

TOKEN = "1316335385:u9xwasdU_d1CyTg0VfdqPb3hlMgcuIpsnu0"
BASE_URL = f"https://tapi.bale.ai/bot{TOKEN}/"

OPENAI_URL = "https://api.groq.com/openai/v1/chat/completions"
OPENAI_API_KEY = "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"

DEFAULT_MODEL = "openai/gpt-oss-120b"

MAIN_ADMIN_ID = 796337622
REQUIRED_CHANNEL = "rayahanel"
REQUIRED_CHANNEL_LINK = "https://ble.ir/rayahanel"
CARD_NUMBER = "6216861957342016"
FREE_DAILY_QUESTIONS = 30
DB_PATH = "btttot_irabs.db"
MAX_MSG_LEN = 4000
MARKUP_MODE = {"dict": False}


def api(method, **params):
    try:
        r = requests.post(BASE_URL + method, json=params, timeout=90)
        return r.json()
    except Exception as e:
        print(f"[API ERROR] {method}: {e}")
        return None


def _prepare_markup(reply_markup):
    if not reply_markup:
        return None
    if MARKUP_MODE["dict"]:
        return reply_markup
    return json.dumps(reply_markup)


def _raw_send(method, chat_id, reply_markup, **extra):
    p = {"chat_id": chat_id}
    p.update(extra)
    rm = _prepare_markup(reply_markup)
    if rm is not None:
        p["reply_markup"] = rm
    return api(method, **p)


def send_message(chat_id, text, reply_markup=None, parse_mode=None):
    text = str(text) if text is not None else ""
    if len(text) > MAX_MSG_LEN:
        parts = [text[i:i + MAX_MSG_LEN] for i in range(0, len(text), MAX_MSG_LEN)]
        last = None
        for i, p in enumerate(parts):
            last = _raw_send("sendMessage", chat_id,
                             reply_markup if i == len(parts) - 1 else None,
                             text=p, parse_mode=parse_mode) if parse_mode else \
                   _raw_send("sendMessage", chat_id,
                             reply_markup if i == len(parts) - 1 else None, text=p)
        return last
    if parse_mode:
        return _raw_send("sendMessage", chat_id, reply_markup, text=text, parse_mode=parse_mode)
    return _raw_send("sendMessage", chat_id, reply_markup, text=text)


def send_photo(chat_id, photo, caption=None, reply_markup=None):
    extra = {"photo": photo}
    if caption:
        extra["caption"] = str(caption)[:1000]
    return _raw_send("sendPhoto", chat_id, reply_markup, **extra)


def send_animation(chat_id, animation, caption=None, reply_markup=None):
    extra = {"animation": animation}
    if caption:
        extra["caption"] = str(caption)[:1000]
    return _raw_send("sendAnimation", chat_id, reply_markup, **extra)


def answer_callback(cb_id, text=None):
    p = {"callback_query_id": cb_id}
    if text:
        p["text"] = text
    return api("answerCallbackQuery", **p)


def get_chat_member(chat_id, user_id):
    return api("getChatMember", chat_id=chat_id, user_id=user_id)


def get_updates(offset=None, timeout=25):
    p = {"timeout": timeout}
    if offset:
        p["offset"] = offset
    return api("getUpdates", **p)


def detect_markup_mode():
    try:
        kb = {"inline_keyboard": [[{"text": "t", "callback_data": "t"}]]}
        r1 = requests.post(BASE_URL + "sendMessage",
                           json={"chat_id": MAIN_ADMIN_ID, "text": ".",
                                 "reply_markup": kb}, timeout=20).json()
        if r1 and r1.get("ok"):
            MARKUP_MODE["dict"] = True
            print("[MARKUP] dict mode")
            return
        r2 = requests.post(BASE_URL + "sendMessage",
                           json={"chat_id": MAIN_ADMIN_ID, "text": ".",
                                 "reply_markup": json.dumps(kb)}, timeout=20).json()
        if r2 and r2.get("ok"):
            MARKUP_MODE["dict"] = False
            print("[MARKUP] JSON string mode")
            return
    except Exception as e:
        print(f"[MARKUP ERROR] {e}")
    MARKUP_MODE["dict"] = False


def openai_chat(model, messages):
    headers = {
        "Authorization": f"Bearer {OPENAI_API_KEY}",
        "Content-Type": "application/json",
    }
    body = {"model": model, "messages": messages}
    try:
        r = requests.post(OPENAI_URL, headers=headers, json=body, timeout=120)
        data = r.json()
        if "choices" in data and data["choices"]:
            return True, data["choices"][0]["message"]["content"]
        err = data.get("error", {}).get("message", "unknown error")
        return False, f"❌ خطای AI: {err}"
    except Exception as e:
        return False, f"❌ خطا در ارتباط با AI: {e}"


def db():
    conn = sqlite3.connect(DB_PATH)
    conn.row_factory = sqlite3.Row
    return conn


def init_db():
    conn = db()
    c = conn.cursor()

    try:
        c.execute("SELECT days FROM plans LIMIT 1")
    except sqlite3.OperationalError:
        c.execute("DROP TABLE IF EXISTS plans")

    try:
        c.execute("SELECT model_id FROM models LIMIT 1")
    except sqlite3.OperationalError:
        c.execute("DROP TABLE IF EXISTS models")

    try:
        c.execute("SELECT sub_daily_limit FROM users LIMIT 1")
    except sqlite3.OperationalError:
        c.execute("DROP TABLE IF EXISTS users")

    c.executescript("""
    CREATE TABLE IF NOT EXISTS users (
        user_id INTEGER PRIMARY KEY,
        username TEXT, first_name TEXT,
        joined_at TEXT, is_approved INTEGER DEFAULT 0,
        daily_used INTEGER DEFAULT 0, last_reset TEXT,
        subscription_end TEXT, sub_daily_limit INTEGER DEFAULT 30,
        is_banned INTEGER DEFAULT 0
    );
    CREATE TABLE IF NOT EXISTS admins (user_id INTEGER PRIMARY KEY);
    CREATE TABLE IF NOT EXISTS plans (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT, days INTEGER, daily_questions INTEGER, price INTEGER
    );
    CREATE TABLE IF NOT EXISTS models (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT, model_id TEXT, is_active INTEGER DEFAULT 1
    );
    CREATE TABLE IF NOT EXISTS tickets (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        user_id INTEGER, message TEXT,
        status TEXT DEFAULT 'open', created_at TEXT, admin_reply TEXT
    );
    CREATE TABLE IF NOT EXISTS receipts (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        user_id INTEGER, plan_id INTEGER, photo_id TEXT,
        status TEXT DEFAULT 'pending', created_at TEXT
    );
    CREATE TABLE IF NOT EXISTS chats (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        user_id INTEGER, title TEXT, created_at TEXT
    );
    CREATE TABLE IF NOT EXISTS messages (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        chat_id INTEGER, user_id INTEGER,
        role TEXT, content TEXT, created_at TEXT
    );
    CREATE TABLE IF NOT EXISTS settings (key TEXT PRIMARY KEY, value TEXT);
    """)
    conn.commit()

    c.execute("SELECT COUNT(*) FROM plans")
    if c.fetchone()[0] == 0:
        c.executemany("INSERT INTO plans (name, days, daily_questions, price) VALUES (?,?,?,?)", [
            ("اشتراک ۱ ماهه", 30, 100, 50000),
            ("اشتراک ۳ ماهه", 90, 200, 120000),
            ("اشتراک ویژه نامحدود", 30, 999999, 200000),
        ])
    c.execute("SELECT COUNT(*) FROM models")
    if c.fetchone()[0] == 0:
        c.execute("INSERT INTO models (name, model_id) VALUES (?,?)", ("Llama 3.3 70B", DEFAULT_MODEL))
    conn.commit()
    conn.close()
    print("✅ Database ready")


def get_user(uid):
    conn = db()
    r = conn.execute("SELECT * FROM users WHERE user_id=?", (uid,)).fetchone()
    conn.close()
    return r


def add_user(uid, uname, fname):
    conn = db()
    if not conn.execute("SELECT user_id FROM users WHERE user_id=?", (uid,)).fetchone():
        conn.execute(
            "INSERT INTO users (user_id, username, first_name, joined_at, last_reset, daily_used, sub_daily_limit, is_approved) "
            "VALUES (?,?,?,?,?,0,?,0)",
            (uid, uname, fname, datetime.now().isoformat(), date.today().isoformat(), FREE_DAILY_QUESTIONS))
        conn.commit()
    conn.close()


def set_approved(uid):
    conn = db()
    conn.execute("UPDATE users SET is_approved=1 WHERE user_id=?", (uid,))
    conn.commit()
    conn.close()


def is_admin(uid):
    if uid == MAIN_ADMIN_ID:
        return True
    conn = db()
    r = conn.execute("SELECT user_id FROM admins WHERE user_id=?", (uid,)).fetchone()
    conn.close()
    return r is not None


def add_admin(uid):
    conn = db()
    conn.execute("INSERT OR IGNORE INTO admins (user_id) VALUES (?)", (uid,))
    conn.commit()
    conn.close()


def all_admin_ids():
    conn = db()
    rows = conn.execute("SELECT user_id FROM admins").fetchall()
    conn.close()
    result = [MAIN_ADMIN_ID]
    for r in rows:
        if r["user_id"] not in result:
            result.append(r["user_id"])
    return result


def get_setting(k, d=None):
    conn = db()
    r = conn.execute("SELECT value FROM settings WHERE key=?", (k,)).fetchone()
    conn.close()
    return r["value"] if r else d


def set_setting(k, v):
    conn = db()
    conn.execute("INSERT OR REPLACE INTO settings (key, value) VALUES (?,?)", (k, v))
    conn.commit()
    conn.close()


def get_plans():
    conn = db()
    rows = conn.execute("SELECT * FROM plans").fetchall()
    conn.close()
    return rows


def get_plan(pid):
    conn = db()
    r = conn.execute("SELECT * FROM plans WHERE id=?", (pid,)).fetchone()
    conn.close()
    return r


def add_plan(name, days, dq, price):
    conn = db()
    conn.execute("INSERT INTO plans (name, days, daily_questions, price) VALUES (?,?,?,?)", (name, days, dq, price))
    conn.commit()
    conn.close()


def delete_plan(pid):
    conn = db()
    conn.execute("DELETE FROM plans WHERE id=?", (pid,))
    conn.commit()
    conn.close()


def get_models(active=True):
    conn = db()
    rows = conn.execute("SELECT * FROM models WHERE is_active=1" if active else "SELECT * FROM models").fetchall()
    conn.close()
    return rows


def add_model(name, mid):
    conn = db()
    conn.execute("INSERT INTO models (name, model_id) VALUES (?,?)", (name, mid))
    conn.commit()
    conn.close()


def toggle_model(mid):
    conn = db()
    conn.execute("UPDATE models SET is_active = 1 - is_active WHERE id=?", (mid,))
    conn.commit()
    conn.close()


def all_users():
    conn = db()
    rows = conn.execute("SELECT user_id FROM users WHERE is_banned=0").fetchall()
    conn.close()
    return [r["user_id"] for r in rows]


def get_tickets(status=None):
    conn = db()
    rows = conn.execute("SELECT * FROM tickets WHERE status=?" if status else "SELECT * FROM tickets",
                        (status,) if status else ()).fetchall()
    conn.close()
    return rows


def add_ticket(uid, msg):
    conn = db()
    cur = conn.execute("INSERT INTO tickets (user_id, message, created_at) VALUES (?,?,?)",
                       (uid, msg, datetime.now().isoformat()))
    tid = cur.lastrowid
    conn.commit()
    conn.close()
    return tid


def update_ticket(tid, status, reply=None):
    conn = db()
    conn.execute("UPDATE tickets SET status=?, admin_reply=? WHERE id=?", (status, reply, tid))
    conn.commit()
    conn.close()


def add_receipt(uid, plan_id, photo_id):
    conn = db()
    cur = conn.execute("INSERT INTO receipts (user_id, plan_id, photo_id, created_at) VALUES (?,?,?,?)",
                       (uid, plan_id, photo_id, datetime.now().isoformat()))
    rid = cur.lastrowid
    conn.commit()
    conn.close()
    return rid


def get_receipt(rid):
    conn = db()
    r = conn.execute("SELECT * FROM receipts WHERE id=?", (rid,)).fetchone()
    conn.close()
    return r


def update_receipt(rid, status):
    conn = db()
    conn.execute("UPDATE receipts SET status=? WHERE id=?", (status, rid))
    conn.commit()
    conn.close()


def reset_daily(uid):
    conn = db()
    r = conn.execute("SELECT last_reset FROM users WHERE user_id=?", (uid,)).fetchone()
    today = date.today().isoformat()
    if r and r["last_reset"] != today:
        conn.execute("UPDATE users SET daily_used=0, last_reset=? WHERE user_id=?", (today, uid))
        conn.commit()
    conn.close()


def check_subscription(uid):
    u = get_user(uid)
    if not u:
        return False, FREE_DAILY_QUESTIONS
    if u["subscription_end"]:
        try:
            end = datetime.fromisoformat(u["subscription_end"])
            if end > datetime.now():
                limit = u["sub_daily_limit"] if u["sub_daily_limit"] else FREE_DAILY_QUESTIONS
                return True, limit
        except Exception:
            pass
    return False, FREE_DAILY_QUESTIONS


def apply_subscription(uid, plan_id):
    conn = db()
    plan = conn.execute("SELECT * FROM plans WHERE id=?", (plan_id,)).fetchone()
    if not plan:
        conn.close()
        return False
    u = conn.execute("SELECT subscription_end FROM users WHERE user_id=?", (uid,)).fetchone()
    base = datetime.now()
    if u and u["subscription_end"]:
        try:
            cur_end = datetime.fromisoformat(u["subscription_end"])
            if cur_end > base:
                base = cur_end
        except Exception:
            pass
    new_end = base + timedelta(days=plan["days"])
    conn.execute(
        "UPDATE users SET subscription_end=?, sub_daily_limit=?, daily_used=0, last_reset=? WHERE user_id=?",
        (new_end.isoformat(), plan["daily_questions"], date.today().isoformat(), uid))
    conn.commit()
    conn.close()
    return True


def create_chat(uid, title):
    conn = db()
    cur = conn.execute("INSERT INTO chats (user_id, title, created_at) VALUES (?,?,?)",
                       (uid, title, datetime.now().isoformat()))
    cid = cur.lastrowid
    conn.commit()
    conn.close()
    return cid


def get_user_chats(uid):
    conn = db()
    rows = conn.execute("SELECT * FROM chats WHERE user_id=? ORDER BY id DESC", (uid,)).fetchall()
    conn.close()
    return rows


def delete_chat(cid):
    conn = db()
    conn.execute("DELETE FROM messages WHERE chat_id=?", (cid,))
    conn.execute("DELETE FROM chats WHERE id=?", (cid,))
    conn.commit()
    conn.close()


def add_message(cid, uid, role, content):
    conn = db()
    conn.execute("INSERT INTO messages (chat_id, user_id, role, content, created_at) VALUES (?,?,?,?,?)",
                 (cid, uid, role, content, datetime.now().isoformat()))
    conn.commit()
    conn.close()


def delete_last_user_message(cid):
    conn = db()
    conn.execute("DELETE FROM messages WHERE id = (SELECT MAX(id) FROM messages WHERE chat_id=? AND role='user')", (cid,))
    conn.commit()
    conn.close()


def get_chat_messages(cid, limit=20):
    conn = db()
    rows = conn.execute("SELECT role, content FROM messages WHERE chat_id=? ORDER BY id DESC LIMIT ?",
                        (cid, limit)).fetchall()
    conn.close()
    return [{"role": r["role"], "content": r["content"]} for r in reversed(rows)]


def main_menu():
    return {
        "keyboard": [
            [{"text": "💬 شروع چت"}],
            [{"text": "🛒 خرید اشتراک"}],
            [{"text": "📞 تیکت پشتیبانی"}, {"text": "📂 مدیریت چت‌ها"}],
        ],
        "resize_keyboard": True
    }


def admin_menu():
    return {"inline_keyboard": [
        [{"text": "📢 پیام همگانی", "callback_data": "adm_broadcast"}],
        [{"text": "✏️ متن خوش‌آمد", "callback_data": "adm_welcome_text"},
         {"text": "🎞 گیف خوش‌آمد", "callback_data": "adm_welcome_gif"}],
        [{"text": "💎 مدیریت اشتراک‌ها", "callback_data": "adm_plans"},
         {"text": "🤖 مدل‌های زبانی", "callback_data": "adm_models"}],
        [{"text": "📩 تیکت‌ها", "callback_data": "adm_tickets"},
         {"text": "👤 افزودن ادمین", "callback_data": "adm_add_admin"}],
    ]}


def back_admin_kb():
    return {"inline_keyboard": [[{"text": "🔙 بازگشت", "callback_data": "adm_back"}]]}


def back_main_kb():
    return {"inline_keyboard": [[{"text": "🔙 بازگشت به منو", "callback_data": "main_menu"}]]}


def join_kb():
    return {"inline_keyboard": [
        [{"text": "✅ عضویت در کانال", "url": REQUIRED_CHANNEL_LINK}],
        [{"text": "🔄 بررسی عضویت", "callback_data": "check_join"}],
    ]}


user_states = {}


def check_membership(uid):
    try:
        res = get_chat_member(f"@{REQUIRED_CHANNEL}", uid)
        if res and res.get("ok"):
            status = res["result"].get("status")
            return status in ["member", "administrator", "creator"]
        return False
    except Exception as e:
        print(f"membership error: {e}")
        return False


def send_welcome(uid, first_name):
    txt = get_setting("welcome_text", "👋 سلام {name}!\nبه ربات هوش مصنوعی خوش آمدید.\nاز منوی زیر انتخاب کنید:")
    txt = txt.replace("{name}", first_name or "کاربر")
    gif = get_setting("welcome_gif")
    if gif:
        res = send_animation(uid, gif, caption=txt, reply_markup=main_menu())
        if not res or not res.get("ok"):
            send_message(uid, txt, reply_markup=main_menu())
    else:
        send_message(uid, txt, reply_markup=main_menu())


def consume_question(uid):
    reset_daily(uid)
    u = get_user(uid)
    if not u:
        return False
    active, limit = check_subscription(uid)
    used = u["daily_used"] if u["daily_used"] is not None else 0
    if used >= limit:
        send_message(uid,
                     f"⚠️ سقف سوالات امروز شما ({limit}) تمام شد.\nبرای سوال بیشتر اشتراک تهیه کنید.",
                     reply_markup=main_menu())
        return False
    conn = db()
    conn.execute("UPDATE users SET daily_used = COALESCE(daily_used, 0) + 1 WHERE user_id=?", (uid,))
    conn.commit()
    conn.close()
    return True


def ai_chat(uid, text):
    state = user_states.get(uid)
    if not state or state.get("state") != "chat":
        return
    cid = state.get("chat_id")
    if not cid:
        cid = create_chat(uid, f"چت {datetime.now().strftime('%H:%M')}")
        state["chat_id"] = cid
    add_message(cid, uid, "user", text)
    history = get_chat_messages(cid, limit=20)
    models = get_models(active=True)
    model_id = models[0]["model_id"] if models else DEFAULT_MODEL
    messages = [{"role": "system", "content": "تو یک دستیار مفید فارسی‌زبان هستی. پاسخ‌ها را کوتاه و مفید بده."}] + history
    ok, answer = openai_chat(model_id, messages)
    if ok:
        add_message(cid, uid, "assistant", answer)
    else:
        delete_last_user_message(cid)
    kb = {"inline_keyboard": [[{"text": "🔚 پایان چت", "callback_data": "end_chat"}]]}
    send_message(uid, answer, reply_markup=kb)


def get_msg_photo_id(msg):
    if msg.get("photo"):
        photos = msg["photo"]
        if isinstance(photos, list) and len(photos) > 0:
            last = photos[-1]
            if isinstance(last, dict) and "file_id" in last:
                return last["file_id"]
        elif isinstance(photos, dict) and "file_id" in photos:
            return photos["file_id"]
    if msg.get("document"):
        doc = msg["document"]
        if isinstance(doc, dict) and "file_id" in doc:
            return doc["file_id"]
    return None


def get_msg_animation_id(msg):
    if msg.get("animation"):
        a = msg["animation"]
        if isinstance(a, dict) and "file_id" in a:
            return a["file_id"]
    if msg.get("document"):
        d = msg["document"]
        if isinstance(d, dict) and "file_id" in d:
            return d["file_id"]
    return None


def handle_message(msg):
    try:
        author = msg.get("from", {})
        uid = author.get("id")
        if not uid:
            return
        text = msg.get("text", "") or ""
        uname = author.get("username", "") or ""
        fname = author.get("first_name", "") or ""
        add_user(uid, uname, fname)

        u = get_user(uid)
        if u and u["is_banned"]:
            return

        if text == "/start":
            user_states.pop(uid, None)
            if not check_membership(uid):
                send_message(uid, "🔒 برای استفاده از ربات ابتدا در کانال ما عضو شوید:", reply_markup=join_kb())
                return
            set_approved(uid)
            send_welcome(uid, fname)
            return

        if text == "/cancel":
            user_states.pop(uid, None)
            send_message(uid, "❌ عملیات کنسل شد.", reply_markup=main_menu())
            return

        if text == "/admin" and is_admin(uid):
            send_message(uid, "👨‍💼 پنل مدیریت:", reply_markup=admin_menu())
            return

        if text.startswith("/"):
            return

        if not u or not u["is_approved"]:
            if not check_membership(uid):
                send_message(uid, "🔒 ابتدا در کانال عضو شوید:", reply_markup=join_kb())
                return
            set_approved(uid)

        state = user_states.get(uid)

        if text == "💬 شروع چت":
            if consume_question(uid):
                cid = create_chat(uid, f"چت {datetime.now().strftime('%Y-%m-%d %H:%M')}")
                user_states[uid] = {"state": "chat", "chat_id": cid}
                kb = {"inline_keyboard": [[{"text": "🔚 پایان چت", "callback_data": "end_chat"}]]}
                send_message(uid, "💬 چت شروع شد. پیام خود را بفرستید.", reply_markup=kb)
            return

        if text == "🛒 خرید اشتراک":
            user_states.pop(uid, None)
            plans = get_plans()
            if not plans:
                send_message(uid, "❌ فعلاً پلنی موجود نیست.", reply_markup=back_main_kb())
                return
            kb = {"inline_keyboard": [[{"text": f"{p['name']} - {p['price']:,} تومان", "callback_data": f"buy_{p['id']}"}] for p in plans]}
            kb["inline_keyboard"].append([{"text": "🔙 بازگشت", "callback_data": "main_menu"}])
            send_message(uid, "💎 پلن مورد نظر را انتخاب کنید:", reply_markup=kb)
            return

        if text == "📞 تیکت پشتیبانی":
            user_states[uid] = {"state": "ticket"}
            send_message(uid, "📝 پیام خود را برای پشتیبانی بنویسید:", reply_markup=back_main_kb())
            return

        if text == "📂 مدیریت چت‌ها":
            user_states.pop(uid, None)
            chats = get_user_chats(uid)
            if not chats:
                send_message(uid, "📭 هیچ چتی ندارید.", reply_markup=back_main_kb())
                return
            kb = {"inline_keyboard": [[{"text": f"🗑 {ch['title']}", "callback_data": f"del_chat_{ch['id']}"}] for ch in chats[:20]]}
            kb["inline_keyboard"].append([{"text": "🔙 بازگشت", "callback_data": "main_menu"}])
            send_message(uid, "📂 برای حذف چت روی آن کلیک کنید:", reply_markup=kb)
            return

        if state and handle_state(uid, text, msg, state):
            return

        if text:
            if consume_question(uid):
                cid = create_chat(uid, f"چت {datetime.now().strftime('%H:%M')}")
                user_states[uid] = {"state": "chat", "chat_id": cid}
                ai_chat(uid, text)
            return
    except Exception as e:
        print(f"handle_message error: {e}")
        traceback.print_exc()


def handle_state(uid, text, msg, state):
    st = state.get("state")

    if st == "chat":
        if text:
            ai_chat(uid, text)
        return True

    if st == "ticket":
        if not text:
            return True
        tid = add_ticket(uid, text)
        user_states.pop(uid, None)
        send_message(uid, f"✅ تیکت #{tid} ثبت شد. پاسخ توسط پشتیبانی ارسال می‌شود.", reply_markup=main_menu())
        for a in all_admin_ids():
            kb = {"inline_keyboard": [
                [{"text": "✍️ پاسخ", "callback_data": f"tk_reply_{tid}"},
                 {"text": "❌ بستن", "callback_data": f"tk_close_{tid}"}]
            ]}
            send_message(a, f"📩 تیکت جدید #{tid}\nاز: {uid}\n\n{text}", reply_markup=kb)
        return True

    if st == "broadcast":
        user_states.pop(uid, None)
        do_broadcast(uid, msg)
        return True

    if st == "welcome_text":
        if not text:
            return True
        set_setting("welcome_text", text)
        user_states.pop(uid, None)
        send_message(uid, "✅ متن خوش‌آمد ذخیره شد.", reply_markup=admin_menu())
        return True

    if st == "welcome_gif":
        gif = get_msg_animation_id(msg)
        if not gif and text:
            gif = text
        if not gif:
            return True
        set_setting("welcome_gif", gif)
        user_states.pop(uid, None)
        send_message(uid, "✅ گیف خوش‌آمد ذخیره شد.", reply_markup=admin_menu())
        return True

    if st == "add_plan":
        parts = text.split("|")
        if len(parts) != 4:
            send_message(uid, "❌ فرمت: نام|روز|سوال روزانه|قیمت")
            return True
        try:
            add_plan(parts[0].strip(), int(parts[1]), int(parts[2]), int(parts[3]))
            user_states.pop(uid, None)
            send_message(uid, "✅ پلن اضافه شد.", reply_markup=admin_menu())
        except Exception:
            send_message(uid, "❌ مقادیر عددی نامعتبر.")
        return True

    if st == "add_model":
        parts = text.split("|")
        if len(parts) != 2:
            send_message(uid, "❌ فرمت: نام|model_id")
            return True
        add_model(parts[0].strip(), parts[1].strip())
        user_states.pop(uid, None)
        send_message(uid, "✅ مدل اضافه شد.", reply_markup=admin_menu())
        return True

    if st == "add_admin":
        try:
            nid = int(text)
            add_admin(nid)
            user_states.pop(uid, None)
            send_message(uid, f"✅ ادمین {nid} اضافه شد.", reply_markup=admin_menu())
        except Exception:
            send_message(uid, "❌ آیدی نامعتبر.")
        return True

    if st == "receipt":
        photo_id = get_msg_photo_id(msg)
        if not photo_id:
            send_message(uid, "❌ لطفاً عکس رسید را ارسال کنید (فقط تصویر).")
            return True
        plan_id = state.get("plan_id")
        rid = add_receipt(uid, plan_id, photo_id)
        user_states.pop(uid, None)
        send_message(uid, "✅ رسید شما ارسال شد و در انتظار تایید ادمین است.", reply_markup=main_menu())
        plan = get_plan(plan_id)
        for a in all_admin_ids():
            kb = {"inline_keyboard": [
                [{"text": "✅ تایید", "callback_data": f"rc_ok_{rid}"},
                 {"text": "❌ رد", "callback_data": f"rc_no_{rid}"}]
            ]}
            send_photo(a, photo_id,
                       caption=f"💳 رسید جدید #{rid}\nکاربر: {uid}\nپلن: {plan['name'] if plan else '?'} ({plan['price'] if plan else '?'} تومان)",
                       reply_markup=kb)
        return True

    if st == "admin_reply_ticket":
        if not text:
            return True
        tid = state.get("ticket_id")
        conn = db()
        t = conn.execute("SELECT user_id FROM tickets WHERE id=?", (tid,)).fetchone()
        conn.close()
        if t:
            update_ticket(tid, "answered", text)
            send_message(t["user_id"], f"📞 پاسخ پشتیبانی به تیکت #{tid}:\n\n{text}")
        user_states.pop(uid, None)
        send_message(uid, "✅ پاسخ ارسال شد.", reply_markup=admin_menu())
        return True

    return False


def do_broadcast(uid, msg):
    text = msg.get("text", "") or ""
    photo_id = get_msg_photo_id(msg)
    users = all_users()
    sent = 0
    failed = 0
    for u in users:
        try:
            if photo_id:
                res = send_photo(u, photo_id, caption=text)
            else:
                res = send_message(u, text)
            if res and res.get("ok"):
                sent += 1
            else:
                failed += 1
            time.sleep(0.06)
        except Exception:
            failed += 1
    send_message(uid, f"✅ ارسال شد: {sent}\n❌ ناموفق: {failed}", reply_markup=admin_menu())


def handle_callback(cb):
    try:
        uid = cb["from"]["id"]
        data = cb["data"]
        cb_id = cb["id"]
        answer_callback(cb_id)

        if data == "check_join":
            if check_membership(uid):
                set_approved(uid)
                send_message(uid, "✅ عضویت تایید شد! /start را بزنید.")
            else:
                send_message(uid, "❌ هنوز عضو کانال نشده‌اید.")
            return

        if data == "main_menu":
            user_states.pop(uid, None)
            send_message(uid, "🏠 منوی اصلی:", reply_markup=main_menu())
            return

        if data == "adm_back":
            send_message(uid, "👨‍💼 پنل مدیریت:", reply_markup=admin_menu())
            return

        if data == "end_chat":
            user_states.pop(uid, None)
            send_message(uid, "🔚 چت پایان یافت.", reply_markup=main_menu())
            return

        if data.startswith("del_chat_"):
            cid = int(data.split("_")[2])
            delete_chat(cid)
            user_states.pop(uid, None)
            send_message(uid, "🗑 چت حذف شد.", reply_markup=main_menu())
            return

        if data.startswith("buy_"):
            pid = int(data.split("_")[1])
            p = get_plan(pid)
            if not p:
                send_message(uid, "❌ پلن یافت نشد.")
                return
            txt = (f"💳 پرداخت\n\n"
                   f"پلن: {p['name']}\n"
                   f"مدت: {p['days']} روز\n"
                   f"سوال روزانه: {p['daily_questions']}\n"
                   f"مبلغ: {p['price']:,} تومان\n\n"
                   f"شماره کارت:\n{CARD_NUMBER}\n\n"
                   f"1️⃣ شماره کارت را کپی کنید.\n"
                   f"2️⃣ مبلغ را واریز کنید.\n"
                   f"3️⃣ عکس رسید را در همین چت ارسال کنید.")
            kb = {"inline_keyboard": [
                [{"text": "📤 ارسال رسید", "callback_data": f"send_rc_{pid}"}],
                [{"text": "🔙 بازگشت", "callback_data": "back_plans"}],
            ]}
            send_message(uid, txt, reply_markup=kb)
            return

        if data == "back_plans":
            plans = get_plans()
            kb = {"inline_keyboard": [[{"text": f"{p['name']} - {p['price']:,} تومان", "callback_data": f"buy_{p['id']}"}] for p in plans]}
            send_message(uid, "💎 پلن مورد نظر را انتخاب کنید:", reply_markup=kb)
            return

        if data.startswith("send_rc_"):
            pid = int(data.split("_")[2])
            user_states[uid] = {"state": "receipt", "plan_id": pid}
            send_message(uid, "📤 لطفاً عکس رسید پرداخت را ارسال کنید:")
            return

        if not is_admin(uid):
            return

        if data == "adm_broadcast":
            user_states[uid] = {"state": "broadcast"}
            send_message(uid, "📢 پیام همگانی را ارسال کنید (متن یا عکس با کپشن).")
            return

        if data == "adm_welcome_text":
            user_states[uid] = {"state": "welcome_text"}
            send_message(uid, "✏️ متن خوش‌آمد جدید را بفرستید.\n(می‌توانید از {name} استفاده کنید)")
            return

        if data == "adm_welcome_gif":
            user_states[uid] = {"state": "welcome_gif"}
            send_message(uid, "🎞 گیف یا لینک گیف را بفرستید:")
            return

        if data == "adm_plans":
            kb = {"inline_keyboard": [[{"text": f"🗑 {p['name']}", "callback_data": f"delplan_{p['id']}"}] for p in get_plans()]}
            kb["inline_keyboard"].append([{"text": "➕ افزودن پلن", "callback_data": "add_plan"}])
            kb["inline_keyboard"].append([{"text": "🔙 بازگشت", "callback_data": "adm_back"}])
            send_message(uid, "💎 مدیریت پلن‌ها:", reply_markup=kb)
            return

        if data == "add_plan":
            user_states[uid] = {"state": "add_plan"}
            send_message(uid, "فرمت ارسال:\nنام|روز|سوال روزانه|قیمت\nمثال:\nماهانه|30|100|50000")
            return

        if data.startswith("delplan_"):
            pid = int(data.split("_")[1])
            delete_plan(pid)
            send_message(uid, "🗑 حذف شد.", reply_markup=admin_menu())
            return

        if data == "adm_models":
            kb = {"inline_keyboard": []}
            for m in get_models(active=False):
                status = "✅" if m["is_active"] else "❌"
                kb["inline_keyboard"].append([{"text": f"{status} {m['name']} ({m['model_id']})", "callback_data": f"tglm_{m['id']}"}])
            kb["inline_keyboard"].append([{"text": "➕ افزودن مدل", "callback_data": "add_model"}])
            kb["inline_keyboard"].append([{"text": "🔙 بازگشت", "callback_data": "adm_back"}])
            send_message(uid, "🤖 مدل‌های زبانی:", reply_markup=kb)
            return

        if data == "add_model":
            user_states[uid] = {"state": "add_model"}
            send_message(uid, "فرمت: نام|model_id\nمثال:\nLlama 3.1 8B|llama-3.1-8b-instant")
            return

        if data.startswith("tglm_"):
            mid = int(data.split("_")[1])
            toggle_model(mid)
            send_message(uid, "✅ تغییر یافت.", reply_markup=admin_menu())
            return

        if data == "adm_tickets":
            tickets = get_tickets("open")
            if not tickets:
                send_message(uid, "📭 تیکت بازی وجود ندارد.", reply_markup=admin_menu())
                return
            for t in tickets:
                kb = {"inline_keyboard": [
                    [{"text": "✍️ پاسخ", "callback_data": f"tk_reply_{t['id']}"},
                     {"text": "❌ بستن", "callback_data": f"tk_close_{t['id']}"}]
                ]}
                send_message(uid, f"📩 تیکت #{t['id']}\nاز: {t['user_id']}\n\n{t['message']}", reply_markup=kb)
            return

        if data.startswith("tk_reply_"):
            tid = int(data.split("_")[2])
            user_states[uid] = {"state": "admin_reply_ticket", "ticket_id": tid}
            send_message(uid, f"✍️ پاسخ تیکت #{tid} را بنویسید:")
            return

        if data.startswith("tk_close_"):
            tid = int(data.split("_")[2])
            update_ticket(tid, "closed")
            send_message(uid, "✅ تیکت بسته شد.", reply_markup=admin_menu())
            return

        if data == "adm_add_admin":
            user_states[uid] = {"state": "add_admin"}
            send_message(uid, "👤 آیدی عددی ادمین جدید را بفرستید:")
            return

        if data.startswith("rc_ok_"):
            rid = int(data.split("_")[2])
            rc = get_receipt(rid)
            if rc and rc["status"] == "pending":
                apply_subscription(rc["user_id"], rc["plan_id"])
                update_receipt(rid, "approved")
                send_message(rc["user_id"], "✅ پرداخت شما تایید شد و اشتراک فعال گردید.")
                send_message(uid, f"✅ رسید #{rid} تایید شد.")
            else:
                send_message(uid, "⚠️ این رسید قبلاً بررسی شده.")
            return

        if data.startswith("rc_no_"):
            rid = int(data.split("_")[2])
            rc = get_receipt(rid)
            if rc and rc["status"] == "pending":
                update_receipt(rid, "rejected")
                send_message(rc["user_id"], "❌ متاسفانه رسید شما رد شد. لطفاً با پشتیبانی تماس بگیرید.")
                send_message(uid, f"❌ رسید #{rid} رد شد.")
            else:
                send_message(uid, "⚠️ این رسید قبلاً بررسی شده.")
            return
    except Exception as e:
        print(f"handle_callback error: {e}")
        traceback.print_exc()


def main():
    init_db()
    me = api("getMe")
    if not me or not me.get("ok"):
        print(f"❌ ربات متصل نشد. پاسخ: {me}")
        return
    print(f"✅ Bot started: @{me['result'].get('username', '?')}")
    try:
        detect_markup_mode()
    except Exception as e:
        print(f"[DETECT ERROR] {e}")
    offset = None
    while True:
        try:
            updates = get_updates(offset=offset, timeout=25)
            if not updates or not updates.get("ok"):
                time.sleep(2)
                continue
            for upd in updates["result"]:
                offset = upd["update_id"] + 1
                try:
                    if "message" in upd:
                        handle_message(upd["message"])
                    elif "callback_query" in upd:
                        handle_callback(upd["callback_query"])
                except Exception as e:
                    print(f"Handler error: {e}")
                    traceback.print_exc()
        except KeyboardInterrupt:
            print("Stopped.")
            break
        except Exception as e:
            print(f"Loop error: {e}")
            time.sleep(3)


if __name__ == "__main__":
    main()