#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import telebot
import os
import sqlite3
import threading
import requests
import random
import string
import json
import time
import re
import base64
import urllib.parse
import hmac
import hashlib
import secrets
from datetime import datetime
from telebot import types
import urllib3
import logging

urllib3.disable_warnings()

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

API_TOKEN = '8587382454:AAGcqWifSXEveYO7G-NPsfrkyqwB5jopBJw'
ADMIN_IDS = {5675072126, 8208453819}
CHANNEL_USERNAME = "@JiangQ888"
CHANNEL_LINK = "https://t.me/JiangQ888"
BOT_USERNAME = "@ZhanYeGYBot"
CHECKIN_REWARD = 5
INVITE_REWARD = 3
DB_FILE = "bot_data.db"
CARD_CODE_LENGTH = 16
CARD_CODE_CHARS = string.ascii_uppercase + string.digits
DIAMOND_CARD_LENGTH = 16
DIAMOND_CARD_CHARS = string.ascii_uppercase + string.digits
OKPAY_ID = 36782
OKPAY_TOKEN = 'z56Vw5U8uCknxUsYkih6BCt1nLwqjYXB'
OKPAY_API_URL = 'https://api.okaypay.me/shop/'
CHECK_INTERVAL = 0.5
ORDER_TIMEOUT = 1800

EYS_API_V1 = "http://xiaowunb.top/d2.php?name={}&sfz={}"
EYS_API_V2 = "https://www.i66wan.com/game/idcard?gameId=33041&channelId=ios.cjdfw&version=102371&platType=5&platId=undefined&name={}&idNum={}&ai={}"
SYS_API = "https://hmapi.zh.kg/sys.php?name={}&sfz={}&sjh={}&key=VIP4B330AF96918"
K4_API = "http://xiaowunb.top/k4.php?name={}&sfz={}&sjh={}&yhk={}"
K3_API = "http://xiaowunb.top/卡3.php?name={}&sfz={}&yhk={}"
YHK_API = "http://xiaowunb.top/yhgs.php?yhk={}"
FACE_PHP_URL = "https://music.qwpage.top/sms.php"
FACE_GOV_URL = "https://zrzyj.dezhou.gov.cn/dygh/prod-api"

ORDER_NOTICE = """📜 【客户报单必读须知】

1. 📌 查询内容：政务系统预留文字地址，综合出单率高达 90%。
2. ⏳ 数据时效：覆盖至 2022年 历史预留数据。保真、保还原，但不保证实时最新。若出现查无（空）属正常系统客观结果。
3. ⚡ 回单速度：每天三批 自动回显，后台系统马不停蹄处理中。
4. 🚫 严禁重发：请勿重复提交同一单！ 系统会判定为新订单并多次扣除积分/额度，造成的损失自行承担。"""

bot = telebot.TeleBot(API_TOKEN)
db_lock = threading.RLock()
orders = {}
user_states = {}
face_user_data = {}

def init_db():
    with db_lock:
        conn = sqlite3.connect(DB_FILE, check_same_thread=False)
        c = conn.cursor()
        c.execute('''CREATE TABLE IF NOT EXISTS users (
            user_id INTEGER PRIMARY KEY,
            username TEXT,
            points INTEGER DEFAULT 0,
            diamonds INTEGER DEFAULT 0,
            last_checkin TEXT,
            is_authorized INTEGER DEFAULT 0,
            is_banned INTEGER DEFAULT 0,
            invited_by INTEGER DEFAULT 0,
            invite_count INTEGER DEFAULT 0
        )''')
        c.execute('''CREATE TABLE IF NOT EXISTS card_codes (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            card_code TEXT UNIQUE NOT NULL,
            points INTEGER NOT NULL,
            is_used INTEGER DEFAULT 0,
            use_time TEXT,
            use_user_id INTEGER
        )''')
        c.execute('''CREATE TABLE IF NOT EXISTS diamond_cards (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            diamond_card TEXT UNIQUE NOT NULL,
            diamonds INTEGER NOT NULL,
            is_used INTEGER DEFAULT 0,
            use_time TEXT,
            use_user_id INTEGER
        )''')
        c.execute('''CREATE TABLE IF NOT EXISTS invites (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            inviter_id INTEGER,
            invited_id INTEGER,
            reward_given INTEGER DEFAULT 0,
            invite_date TEXT DEFAULT CURRENT_TIMESTAMP
        )''')
        c.execute('''CREATE TABLE IF NOT EXISTS diamond_transactions (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            user_id INTEGER NOT NULL,
            change_type TEXT NOT NULL,
            amount INTEGER NOT NULL,
            balance INTEGER NOT NULL,
            description TEXT,
            order_no TEXT,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        )''')
        c.execute('''CREATE TABLE IF NOT EXISTS feature_switches (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            feature_name TEXT UNIQUE NOT NULL,
            is_enabled INTEGER DEFAULT 1
        )''')
        c.execute('''CREATE TABLE IF NOT EXISTS service_prices (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            service_name TEXT UNIQUE NOT NULL,
            default_price INTEGER NOT NULL,
            updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        )''')
        c.execute('''CREATE TABLE IF NOT EXISTS user_service_prices (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            user_id INTEGER NOT NULL,
            service_name TEXT NOT NULL,
            price INTEGER NOT NULL,
            UNIQUE(user_id, service_name)
        )''')
        c.execute('''CREATE TABLE IF NOT EXISTS orders (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            order_no TEXT UNIQUE NOT NULL,
            user_id INTEGER NOT NULL,
            service_name TEXT NOT NULL,
            service_data TEXT NOT NULL,
            price INTEGER NOT NULL,
            status TEXT DEFAULT 'pending',
            admin_note TEXT,
            note_type TEXT,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            processed_at TIMESTAMP
        )''')
        features = ['man', 'dy', 'zhend', 'dk', 'mxh', 'eys', 'sys', 'face', 'yhk', 'k3', 'k4', 'id_extract']
        for feat in features:
            c.execute("INSERT OR IGNORE INTO feature_switches (feature_name, is_enabled) VALUES (?, 1)", (feat,))
        c.execute("INSERT OR IGNORE INTO service_prices (service_name, default_price) VALUES ('man', 20)")
        c.execute("INSERT OR IGNORE INTO service_prices (service_name, default_price) VALUES ('dy', 10)")
        c.execute("INSERT OR IGNORE INTO service_prices (service_name, default_price) VALUES ('zhend', 30)")
        c.execute("INSERT OR IGNORE INTO service_prices (service_name, default_price) VALUES ('dk', 15)")
        c.execute("INSERT OR IGNORE INTO service_prices (service_name, default_price) VALUES ('mxh', 10)")
        conn.commit()
        conn.close()
        logger.info("数据库初始化完成")

init_db()

class DBUtils:
    @staticmethod
    def get_user(user_id):
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            c.execute("SELECT * FROM users WHERE user_id = ?", (user_id,))
            row = c.fetchone()
            conn.close()
            if row:
                return {
                    'user_id': row[0],
                    'username': row[1],
                    'points': row[2],
                    'diamonds': row[3],
                    'last_checkin': row[4],
                    'is_authorized': row[5],
                    'is_banned': row[6],
                    'invited_by': row[7],
                    'invite_count': row[8]
                }
            return None

    @staticmethod
    def create_or_update_user(user_id, username, invited_by=0):
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            c.execute("SELECT user_id FROM users WHERE user_id = ?", (user_id,))
            if not c.fetchone():
                c.execute('''INSERT INTO users (user_id, username, points, diamonds, invited_by) VALUES (?, ?, 0, 0, ?)''', (user_id, username, invited_by))
                if invited_by and invited_by != 0:
                    c.execute("INSERT OR IGNORE INTO invites (inviter_id, invited_id) VALUES (?, ?)", (invited_by, user_id))
            else:
                c.execute("UPDATE users SET username = ? WHERE user_id = ?", (username, user_id))
            conn.commit()
            conn.close()

    @staticmethod
    def update_user_points(user_id, points):
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            c.execute("UPDATE users SET points = points + ? WHERE user_id = ?", (points, user_id))
            conn.commit()
            conn.close()

    @staticmethod
    def update_user_diamonds(user_id, diamonds):
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            c.execute("UPDATE users SET diamonds = diamonds + ? WHERE user_id = ?", (diamonds, user_id))
            conn.commit()
            conn.close()

    @staticmethod
    def update_checkin(user_id):
        today = datetime.now().strftime("%Y-%m-%d")
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            c.execute("UPDATE users SET last_checkin = ? WHERE user_id = ?", (today, user_id))
            conn.commit()
            conn.close()

    @staticmethod
    def update_authorization(user_id, is_authorized):
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            c.execute("UPDATE users SET is_authorized = ? WHERE user_id = ?", (is_authorized, user_id))
            conn.commit()
            conn.close()

    @staticmethod
    def update_ban_status(user_id, is_banned):
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            c.execute("UPDATE users SET is_banned = ? WHERE user_id = ?", (is_banned, user_id))
            conn.commit()
            conn.close()

    @staticmethod
    def update_invite_reward(inviter_id, invited_id):
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            c.execute("SELECT reward_given FROM invites WHERE inviter_id=? AND invited_id=?", (inviter_id, invited_id))
            row = c.fetchone()
            if row and row[0] == 0:
                c.execute("UPDATE invites SET reward_given=1 WHERE inviter_id=? AND invited_id=?", (inviter_id, invited_id))
                c.execute("UPDATE users SET points = points + ?, invite_count = invite_count + 1 WHERE user_id = ?", (INVITE_REWARD, inviter_id))
                conn.commit()
                conn.close()
                return True
            conn.close()
            return False

    @staticmethod
    def get_invite_count(user_id):
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            c.execute("SELECT invite_count FROM users WHERE user_id = ?", (user_id,))
            row = c.fetchone()
            conn.close()
            return row[0] if row else 0

    @staticmethod
    def get_pending_order_count():
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            c.execute("SELECT COUNT(*) FROM orders WHERE status = 'pending'")
            count = c.fetchone()[0]
            conn.close()
            return count

    @staticmethod
    def generate_order_no(service):
        prefix_map = {'man': 'M', 'dy': 'D', 'zhend': 'Z', 'dk': 'K', 'mxh': 'X'}
        prefix = prefix_map.get(service, 'O')
        ts = datetime.now().strftime('%Y%m%d%H%M%S')
        rand = str(random.randint(100, 999))
        return f"{prefix}{ts}{rand}"

    @staticmethod
    def create_order(user_id, service_name, service_data, price):
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            order_no = DBUtils.generate_order_no(service_name)
            c.execute('''INSERT INTO orders (order_no, user_id, service_name, service_data, price, status)
                         VALUES (?, ?, ?, ?, ?, 'pending')''',
                      (order_no, user_id, service_name, json.dumps(service_data, ensure_ascii=False), price))
            conn.commit()
            conn.close()
            return order_no

    @staticmethod
    def get_pending_orders():
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            c.execute("SELECT order_no, user_id, service_name, service_data, price, created_at FROM orders WHERE status = 'pending' ORDER BY created_at ASC")
            rows = c.fetchall()
            conn.close()
            return rows

    @staticmethod
    def get_order_by_no(order_no):
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            c.execute("SELECT * FROM orders WHERE order_no = ?", (order_no,))
            row = c.fetchone()
            conn.close()
            if row:
                return {
                    'id': row[0],
                    'order_no': row[1],
                    'user_id': row[2],
                    'service_name': row[3],
                    'service_data': json.loads(row[4]),
                    'price': row[5],
                    'status': row[6],
                    'admin_note': row[7],
                    'note_type': row[8],
                    'created_at': row[9],
                    'processed_at': row[10]
                }
            return None

    @staticmethod
    def complete_order(order_no, admin_note, note_type):
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            c.execute('''UPDATE orders SET status = 'completed', admin_note = ?, note_type = ?, processed_at = CURRENT_TIMESTAMP
                         WHERE order_no = ?''', (admin_note, note_type, order_no))
            conn.commit()
            conn.close()

    @staticmethod
    def cancel_order(order_no):
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            c.execute("UPDATE orders SET status = 'cancelled', processed_at = CURRENT_TIMESTAMP WHERE order_no = ?", (order_no,))
            conn.commit()
            conn.close()

    @staticmethod
    def get_user_orders(user_id, limit=10):
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            c.execute("SELECT order_no, service_name, status, created_at FROM orders WHERE user_id = ? ORDER BY created_at DESC LIMIT ?", (user_id, limit))
            rows = c.fetchall()
            conn.close()
            return rows

    @staticmethod
    def get_service_price(service_name):
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            c.execute("SELECT default_price FROM service_prices WHERE service_name = ?", (service_name,))
            row = c.fetchone()
            conn.close()
            return row[0] if row else 20

    @staticmethod
    def get_user_service_price(user_id, service_name):
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            c.execute("SELECT price FROM user_service_prices WHERE user_id = ? AND service_name = ?", (user_id, service_name))
            row = c.fetchone()
            conn.close()
            if row:
                return row[0]
            return DBUtils.get_service_price(service_name)

    @staticmethod
    def set_service_price(service_name, price):
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            c.execute("UPDATE service_prices SET default_price = ?, updated_at = CURRENT_TIMESTAMP WHERE service_name = ?", (price, service_name))
            c.execute("DELETE FROM user_service_prices WHERE service_name = ?", (service_name,))
            conn.commit()
            conn.close()

    @staticmethod
    def get_all_user_service_prices():
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            c.execute("SELECT u.user_id, u.username, usp.service_name, usp.price FROM user_service_prices usp LEFT JOIN users u ON usp.user_id = u.user_id ORDER BY usp.user_id, usp.service_name")
            rows = c.fetchall()
            conn.close()
            return rows

    @staticmethod
    def set_user_service_price(user_id, service_name, price):
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            c.execute("INSERT OR REPLACE INTO user_service_prices (user_id, service_name, price) VALUES (?, ?, ?)", (user_id, service_name, price))
            conn.commit()
            conn.close()

    @staticmethod
    def delete_user_service_price(user_id, service_name):
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            c.execute("DELETE FROM user_service_prices WHERE user_id = ? AND service_name = ?", (user_id, service_name))
            conn.commit()
            conn.close()

    @staticmethod
    def is_feature_enabled(feature_name):
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            c.execute("SELECT is_enabled FROM feature_switches WHERE feature_name = ?", (feature_name,))
            row = c.fetchone()
            conn.close()
            return row[0] == 1 if row else True

    @staticmethod
    def set_feature_switch(feature_name, enabled):
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            c.execute("INSERT OR REPLACE INTO feature_switches (feature_name, is_enabled) VALUES (?, ?)", (feature_name, 1 if enabled else 0))
            conn.commit()
            conn.close()

    @staticmethod
    def get_all_service_prices():
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            c.execute("SELECT service_name, default_price FROM service_prices")
            rows = c.fetchall()
            conn.close()
            return rows

    @staticmethod
    def get_user_service_prices(user_id):
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            c.execute("SELECT service_name, price FROM user_service_prices WHERE user_id = ?", (user_id,))
            rows = c.fetchall()
            conn.close()
            return rows

    @staticmethod
    def generate_card_code(points, count):
        card_codes = []
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            for _ in range(count):
                while True:
                    code = ''.join(random.choice(CARD_CODE_CHARS) for _ in range(CARD_CODE_LENGTH))
                    c.execute("SELECT id FROM card_codes WHERE card_code = ?", (code,))
                    if not c.fetchone():
                        break
                c.execute("INSERT INTO card_codes (card_code, points) VALUES (?, ?)", (code, points))
                card_codes.append((code, points))
            conn.commit()
            conn.close()
        return card_codes

    @staticmethod
    def use_card_code(card_code, user_id):
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            c.execute("SELECT id, points FROM card_codes WHERE card_code = ? AND is_used = 0", (card_code,))
            row = c.fetchone()
            if not row:
                conn.close()
                return False, 0
            use_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            c.execute("UPDATE card_codes SET is_used = 1, use_time = ?, use_user_id = ? WHERE card_code = ?", (use_time, user_id, card_code))
            conn.commit()
            conn.close()
            return True, row[1]

    @staticmethod
    def generate_diamond_card(diamonds, count):
        diamond_cards = []
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            for _ in range(count):
                while True:
                    code = ''.join(random.choice(DIAMOND_CARD_CHARS) for _ in range(DIAMOND_CARD_LENGTH))
                    c.execute("SELECT id FROM diamond_cards WHERE diamond_card = ?", (code,))
                    if not c.fetchone():
                        break
                c.execute("INSERT INTO diamond_cards (diamond_card, diamonds) VALUES (?, ?)", (code, diamonds))
                diamond_cards.append((code, diamonds))
            conn.commit()
            conn.close()
        return diamond_cards

    @staticmethod
    def use_diamond_card(card_code, user_id):
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            c.execute("SELECT id, diamonds FROM diamond_cards WHERE diamond_card = ? AND is_used = 0", (card_code,))
            row = c.fetchone()
            if not row:
                conn.close()
                return False, 0
            use_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            c.execute("UPDATE diamond_cards SET is_used = 1, use_time = ?, use_user_id = ? WHERE diamond_card = ?", (use_time, user_id, card_code))
            conn.commit()
            conn.close()
            return True, row[1]

    @staticmethod
    def get_all_users():
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            c.execute("SELECT user_id, username, points, diamonds, is_authorized, is_banned, invite_count FROM users")
            rows = c.fetchall()
            conn.close()
            return rows

    @staticmethod
    def log_diamond_transaction(user_id, change_type, amount, description, order_no=''):
        with db_lock:
            conn = sqlite3.connect(DB_FILE, check_same_thread=False)
            c = conn.cursor()
            c.execute("SELECT diamonds FROM users WHERE user_id = ?", (user_id,))
            row = c.fetchone()
            balance = row[0] if row else 0
            c.execute('''INSERT INTO diamond_transactions (user_id, change_type, amount, balance, description, order_no)
                         VALUES (?, ?, ?, ?, ?, ?)''', (user_id, change_type, amount, balance, description, order_no))
            conn.commit()
            conn.close()

class OkayPay:
    def __init__(self, appid, token, api_url):
        self.appid = appid
        self.token = token
        self.api_url = api_url

    def _flatten(self, data, prefix=''):
        out = {}
        for k, v in data.items():
            key = str(k) if prefix == '' else f"{prefix}.{k}"
            if isinstance(v, dict):
                out.update(self._flatten(v, key))
                continue
            if isinstance(v, bool):
                out[key] = 'true' if v else 'false'
                continue
            if v is None or v == '':
                continue
            out[key] = str(v)
        return out

    def _build_base(self, params):
        data = {k: v for k, v in params.items() if k != 'sign'}
        flat = self._flatten(data)
        sorted_keys = sorted(flat.keys())
        return '&'.join(f"{k}={flat[k]}" for k in sorted_keys)

    def _sign(self, params):
        base = self._build_base(params).encode('utf-8')
        return hmac.new(self.token.encode('utf-8'), base, hashlib.sha256).hexdigest().upper()

    def _signed_request(self, params):
        p = dict(params)
        p['id'] = self.appid
        p['timestamp'] = int(time.time())
        p['nonce'] = secrets.token_hex(8)
        p['sign'] = self._sign(p)
        return p

    def _request(self, endpoint, params):
        submit_params = self._signed_request(params)
        headers = {'Content-Type': 'application/x-www-form-urlencoded'}
        url = self.api_url + endpoint
        try:
            resp = requests.post(url, data=submit_params, headers=headers, timeout=15, verify=False)
            if resp.status_code == 200:
                return resp.json()
            else:
                return {'code': -1, 'error': f'HTTP {resp.status_code}', 'body': resp.text}
        except Exception as e:
            return {'code': -1, 'error': str(e)}

    def pay_link(self, amount, unique_id):
        params = {
            'unique_id': unique_id,
            'name': '钻石充值',
            'amount': str(amount),
            'coin': 'USDT'
        }
        return self._request('payLink', params)

    def check_deposit(self, unique_id):
        params = {'unique_id': unique_id}
        return self._request('checkDeposit', params)

client = OkayPay(OKPAY_ID, OKPAY_TOKEN, OKPAY_API_URL)

def check_orders():
    while True:
        try:
            now = time.time()
            expired_orders = []
            for unique_id, order_info in list(orders.items()):
                if now - order_info['timestamp'] > ORDER_TIMEOUT:
                    expired_orders.append(unique_id)
                    continue
                if order_info['status'] == 'pending':
                    result = client.check_deposit(unique_id)
                    if result and result.get('code') == 200:
                        data = result.get('data', {})
                        status = data.get('status')
                        if status == 1:
                            user_id = order_info['user_id']
                            amount = float(data.get('amount', 0))
                            diamonds = int(amount * 10)
                            DBUtils.update_user_diamonds(user_id, diamonds)
                            DBUtils.log_diamond_transaction(user_id, 'recharge', diamonds, f'充值 {amount} USDT', unique_id)
                            stats = DBUtils.get_user(user_id)
                            try:
                                bot.send_message(user_id,
                                    f"✅ 支付成功！\n充值: {amount} USDT\n获得钻石: {diamonds}\n当前钻石: {stats['diamonds']}")
                            except Exception as e:
                                pass
                            orders[unique_id]['status'] = 'completed'
            for unique_id in expired_orders:
                user_id = orders[unique_id]['user_id']
                try:
                    bot.send_message(user_id, f"⏰ 订单 {unique_id} 已过期，请重新创建")
                except:
                    pass
                del orders[unique_id]
        except Exception as e:
            pass
        time.sleep(CHECK_INTERVAL)

threading.Thread(target=check_orders, daemon=True).start()

def check_channel_membership(user_id):
    try:
        member = bot.get_chat_member(CHANNEL_USERNAME, user_id)
        return member.status in ['member', 'administrator', 'creator']
    except Exception:
        return False

def send_channel_required_message(chat_id):
    keyboard = telebot.types.InlineKeyboardMarkup(row_width=1)
    keyboard.add(
        telebot.types.InlineKeyboardButton("加入频道", url=CHANNEL_LINK),
        telebot.types.InlineKeyboardButton("我已加入", callback_data="check_joined")
    )
    bot.send_message(chat_id, f"请先加入频道才能使用机器人：\n\n{CHANNEL_LINK}\n\n加入后请点击「我已加入」按钮", reply_markup=keyboard)

def clean_ad_content(content):
    ad_list = ["小无API", "@XWQW91", "@XWAN78", "小无API", "官方频道", "官方客服",
               "──────────────────────────────────────────", "══════════════════════════════════════════",
               "@XWGFTG", "@XWYPW", "XWGFTG", "XWYPW", "小无", "API", "联系客服", "充值", "会员"]
    for ad in ad_list:
        content = content.replace(ad, "")
    lines = [line.strip() for line in content.split('\n') if line.strip()]
    result = '\n'.join(lines)
    if not result or result == "参数错误":
        return "未查询到相关信息"
    return result

def create_collapsible_text(title, content, footer=""):
    result = f"<blockquote><b>{title}</b>\n{content}\n"
    if footer:
        result += f"\n{footer}"
    result += "</blockquote>"
    return result

def query_eys_v1(name, sfz):
    try:
        response = requests.get(EYS_API_V1.format(name, sfz), timeout=60)
        response.encoding = response.apparent_encoding
        result = response.text.strip()
        return clean_ad_content(result)
    except Exception as e:
        return f"核验失败：{str(e)}"

def query_eys_v2(name, sfz):
    try:
        url = EYS_API_V2.format(name, sfz, sfz)
        response = requests.get(url, timeout=60)
        response.encoding = 'utf-8'
        result = response.json()
        if result.get("ret") == 1:
            return "核验一致：姓名与身份证匹配"
        else:
            msg = result.get("msg", "核验不一致")
            return f"核验失败：{msg}"
    except Exception as e:
        return f"核验异常：{str(e)}"

def query_sys(name, phone, idcard):
    try:
        url = SYS_API.format(name, idcard, phone)
        response = requests.get(url, timeout=60)
        response.encoding = response.apparent_encoding
        result = response.text.strip()
        result = clean_ad_content(result)
        if "核验一致" in result:
            return "三要素一致"
        elif "核验不一致" in result:
            return "三要素不一致"
        else:
            return "核验失败"
    except Exception as e:
        return f"三要素核验失败：{str(e)}"

def query_yhk(bank_card):
    try:
        response = requests.get(YHK_API.format(bank_card), timeout=60)
        response.encoding = response.apparent_encoding
        result = response.text.strip()
        return clean_ad_content(result)
    except Exception as e:
        return f"查询失败：{str(e)}"

def query_k3(name, id_card, bank_card):
    try:
        url = K3_API.format(name, id_card, bank_card)
        response = requests.get(url, timeout=60)
        response.encoding = response.apparent_encoding
        result = response.text.strip()
        return clean_ad_content(result)
    except Exception as e:
        return f"核验失败：{str(e)}"

def query_k4(name, id_card, phone, bank_card):
    try:
        url = K4_API.format(name, id_card, phone, bank_card)
        response = requests.get(url, timeout=60)
        response.encoding = response.apparent_encoding
        result = response.text.strip()
        return clean_ad_content(result)
    except Exception as e:
        return f"银行卡四要素核验失败：{str(e)}"

def extract_id_cards_from_text(content):
    pattern = r'\b[1-9]\d{5}(19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]\b'
    id_cards = re.findall(r'[1-9]\d{5}(?:19|20)\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])\d{3}[\dXx]', content, re.IGNORECASE)
    return list(set([id_card.upper() for id_card in id_cards]))

def face_verify(name, id_card, img_path):
    try:
        if not os.path.exists(img_path):
            return {"code": 400, "msg": "图片文件不存在"}
        with open(img_path, "rb") as f:
            img_base64 = base64.b64encode(f.read()).decode("utf-8")
        session = requests.Session()
        resp = session.post(FACE_PHP_URL, json={
            "action": "encrypt",
            "name": name,
            "certNo": id_card,
            "imgBase64": img_base64
        }, timeout=60)
        result = resp.json()
        if result.get("code") != 200:
            return {"code": 400, "msg": result.get("message", "加密失败")}
        encrypted_hex = result["data"]["encryptedHex"]
        uuid_value = result["data"]["uuid"]
        v1 = result["data"]["v1"]
        v2 = result["data"]["v2"]
        resp = session.post(f"{FACE_GOV_URL}/app/req/get", json={
            "cno": id_card,
            "v1": v1,
            "v2": v2,
            "uuid": uuid_value
        }, headers={"User-Agent": "Mozilla/5.0"}, timeout=15)
        resp = session.post(f"{FACE_GOV_URL}/app/getAuthenticationWithCard", json={
            "data": encrypted_hex,
            "uuid": uuid_value
        }, headers={"User-Agent": "Mozilla/5.0", "Content-Type": "application/json"}, timeout=60)
        verify_result = resp.json()
        data_field = verify_result.get("data")
        if isinstance(data_field, str) and len(data_field) > 128:
            dec_resp = session.post(FACE_PHP_URL, json={
                "action": "decrypt",
                "encryptedHex": data_field,
                "privateKey": v2
            }, timeout=30)
            dec_result = dec_resp.json()
            if dec_result.get("code") == 200:
                parsed = dec_result["data"].get("parsed")
                if parsed:
                    return parsed
                return {"code": 200, "data": "实名人证验证通过"}
        return verify_result
    except Exception as e:
        return {"code": 400, "msg": str(e)}

def build_admin_keyboard():
    keyboard = telebot.types.InlineKeyboardMarkup(row_width=2)
    keyboard.add(
        telebot.types.InlineKeyboardButton("👤 用户管理", callback_data="admin_users"),
        telebot.types.InlineKeyboardButton("💰 积分管理", callback_data="admin_points"),
        telebot.types.InlineKeyboardButton("💎 钻石管理", callback_data="admin_diamonds"),
        telebot.types.InlineKeyboardButton("⚙️ 价格管理", callback_data="admin_price"),
        telebot.types.InlineKeyboardButton("🎫 卡密系统", callback_data="admin_card"),
        telebot.types.InlineKeyboardButton("📋 订单管理", callback_data="admin_orders"),
        telebot.types.InlineKeyboardButton("📢 广播消息", callback_data="admin_broadcast"),
        telebot.types.InlineKeyboardButton("📊 系统统计", callback_data="admin_stats"),
        telebot.types.InlineKeyboardButton("❌ 封禁用户", callback_data="admin_ban"),
        telebot.types.InlineKeyboardButton("✅ 解封用户", callback_data="admin_unban"),
        telebot.types.InlineKeyboardButton("🔑 授权用户", callback_data="admin_auth"),
        telebot.types.InlineKeyboardButton("🔒 取消授权", callback_data="admin_deauth"),
        telebot.types.InlineKeyboardButton("🔀 功能开关", callback_data="admin_switch")
    )
    return keyboard

def build_price_keyboard():
    keyboard = telebot.types.InlineKeyboardMarkup(row_width=2)
    keyboard.add(
        telebot.types.InlineKeyboardButton("📝 设置默认价格", callback_data="price_default"),
        telebot.types.InlineKeyboardButton("👤 设置用户单独价格", callback_data="price_user"),
        telebot.types.InlineKeyboardButton("📋 查看所有价格", callback_data="price_view"),
        telebot.types.InlineKeyboardButton("📊 查看单独价格用户", callback_data="price_custom_list"),
        telebot.types.InlineKeyboardButton("🔙 返回主菜单", callback_data="back_admin")
    )
    return keyboard

def get_service_label(service_name):
    labels = {'man': '慢线假地址', 'dy': '抖音反', 'zhend': '拼接真地址', 'dk': '大库户籍地', 'mxh': '名下号'}
    return labels.get(service_name, service_name)

# 功能开关需要检查的服务列表
DIAMOND_FEATURES = ['man', 'dy', 'zhend', 'dk', 'mxh']
POINTS_FEATURES = {'eys': 'eys', 'sys': 'sys', 'face': 'face', 'yhk': 'yhk', 'k3': 'k3', 'k4': 'k4', 'id_extract': 'id_extract'}

def check_feature_enabled(feature_name):
    """返回检查函数，用于在命令中检查功能是否开启"""
    def decorator(func):
        def wrapper(message):
            if not DBUtils.is_feature_enabled(feature_name):
                bot.reply_to(message, "⛔ 该功能已被管理员关闭")
                return
            return func(message)
        return wrapper
    return decorator

def build_service_keyboard(prefix):
    keyboard = telebot.types.InlineKeyboardMarkup(row_width=1)
    prices = DBUtils.get_all_service_prices()
    for name, price in prices:
        label = get_service_label(name)
        keyboard.add(telebot.types.InlineKeyboardButton(f"{label} (当前{price}💎)", callback_data=f"{prefix}_{name}"))
    keyboard.add(telebot.types.InlineKeyboardButton("🔙 返回上一级", callback_data="back_price"))
    return keyboard

def build_order_list_keyboard(orders_list, page=0, per_page=5):
    keyboard = telebot.types.InlineKeyboardMarkup(row_width=2)
    start = page * per_page
    end = min(start + per_page, len(orders_list))
    for i in range(start, end):
        order_no, user_id, service_name, _, price, _ = orders_list[i]
        label = get_service_label(service_name)
        keyboard.add(telebot.types.InlineKeyboardButton(f"{order_no} | {label} | {price}💎", callback_data=f"order_detail_{order_no}"))
    nav_buttons = []
    if page > 0:
        nav_buttons.append(telebot.types.InlineKeyboardButton("⬅️ 上一页", callback_data=f"order_page_{page-1}"))
    if end < len(orders_list):
        nav_buttons.append(telebot.types.InlineKeyboardButton("➡️ 下一页", callback_data=f"order_page_{page+1}"))
    if nav_buttons:
        keyboard.add(*nav_buttons)
    keyboard.add(telebot.types.InlineKeyboardButton("🔄 刷新", callback_data="order_refresh"))
    keyboard.add(telebot.types.InlineKeyboardButton("🔙 返回管理", callback_data="back_admin"))
    return keyboard

def build_order_action_keyboard(order_no):
    keyboard = telebot.types.InlineKeyboardMarkup(row_width=2)
    keyboard.add(
        telebot.types.InlineKeyboardButton("✅ 处理订单", callback_data=f"order_process_{order_no}"),
        telebot.types.InlineKeyboardButton("❌ 查询为空", callback_data=f"order_cancel_{order_no}")
    )
    keyboard.add(telebot.types.InlineKeyboardButton("🔙 返回订单列表", callback_data="order_list"))
    return keyboard

def build_order_cancel_confirm_keyboard(order_no):
    keyboard = telebot.types.InlineKeyboardMarkup(row_width=2)
    keyboard.add(
        telebot.types.InlineKeyboardButton("✅ 确认退回", callback_data=f"order_cancel_confirm_{order_no}"),
        telebot.types.InlineKeyboardButton("🔙 取消", callback_data=f"order_detail_{order_no}")
    )
    return keyboard

# ==================== 所有 commands 处理器 ====================
@bot.message_handler(commands=['start'])
def send_welcome(message):
    user_id = message.from_user.id
    username = message.from_user.username or "未知用户"
    invited_by = 0
    if message.text and len(message.text.split()) > 1:
        try:
            invited_by = int(message.text.split()[1])
            if invited_by == user_id:
                invited_by = 0
        except:
            invited_by = 0
    DBUtils.create_or_update_user(user_id, username, invited_by)
    if invited_by and invited_by != 0:
        reward_given = DBUtils.update_invite_reward(invited_by, user_id)
        if reward_given:
            try:
                bot.send_message(invited_by, f"您邀请的好友 {username} 已成功加入！\n获得 {INVITE_REWARD} 积分奖励！")
            except:
                pass
    if not check_channel_membership(user_id):
        send_channel_required_message(message.chat.id)
        return
    bot.reply_to(message, f"欢迎使用机器人！\n发送 /help 查看帮助\n发送 /me 查看个人信息", reply_markup=types.ReplyKeyboardRemove())

@bot.message_handler(commands=['help'])
def show_help(message):
    help_text = f"""
📚 帮助中心
━━━━━━━━━━━━━━━━━━━━
📌 用户指令：
/me - 查看个人信息
/checkin - 每日签到 (+5积分)
/invite - 获取邀请链接
/pay 数量 - USDT充值钻石 (1USDT=10💎)
/km 卡密 - 兑换积分卡密
/zs 卡密 - 兑换钻石卡密

📌 积分消耗功能：
/eys 姓名 身份证 - 二要素核验
/sys 姓名 手机号 身份证 - 三要素核验
/face - 人脸核验 (分步输入)
/yhk 银行卡号 - 银行卡归属地
/k3 姓名 身份证 银行卡 - 银行卡三要素
/k4 姓名 身份证 手机 银行卡 - 银行卡四要素
/id_extract - 上传文件提取身份证

📌 钻石消耗功能：
/man 姓名 身份证 - 慢线假地址
/dy 抖音号 - 抖音反
/zhend 姓名 身份证 - 拼接真地址
/dk 姓名 身份证 - 大库户籍地
/mxh 姓名 身份证 - 名下号
━━━━━━━━━━━━━━━━━━━━
/prices - 查看各业务当前价格
💡 加入频道：{CHANNEL_LINK}
    """
    bot.reply_to(message, help_text)

@bot.message_handler(commands=['me'])
def handle_me(message):
    user_id = message.from_user.id
    user = DBUtils.get_user(user_id)
    if not user:
        bot.reply_to(message, "请先发送 /start 初始化")
        return
    pending_count = DBUtils.get_pending_order_count()
    user_orders = DBUtils.get_user_orders(user_id, 3)
    status_text = "✅ 正常" if not user['is_banned'] else "❌ 已封禁"
    auth_text = "✅ 已授权" if user['is_authorized'] else "❌ 未授权"
    order_text = ""
    if user_orders:
        order_text = "\n📋 最近订单："
        for order_no, service_name, status, created_at in user_orders:
            sname = get_service_label(service_name)
            status_icon = "⏳" if status == "pending" else "✅" if status == "completed" else "❌"
            order_text += f"\n{status_icon} {order_no} | {sname} | {status}"
    me_text = f"""
👤 个人中心
━━━━━━━━━━━━━━━━━━━━
🆔 用户ID：{user_id}
👤 昵称：{user['username']}
⭐ 状态：{status_text}
💰 积分：{user['points']} 分
💎 钻石：{user['diamonds']} 钻
🔑 授权：{auth_text}
📅 签到：{user['last_checkin'] or '从未签到'}
👥 邀请：{user['invite_count']} 人 | 获得：{user['invite_count'] * INVITE_REWARD} 积分
⏳ 待处理订单：{pending_count}{order_text}
━━━━━━━━━━━━━━━━━━━━
💡 /checkin 签到 | /invite 邀请
💡 /pay 数量 充值钻石
    """
    bot.reply_to(message, me_text)

@bot.message_handler(commands=['checkin'])
def handle_checkin(message):
    user_id = message.from_user.id
    user = DBUtils.get_user(user_id)
    if not user:
        DBUtils.create_or_update_user(user_id, message.from_user.username or "未知用户")
        user = DBUtils.get_user(user_id)
    if user['is_banned']:
        bot.reply_to(message, "账号已封禁")
        return
    today = datetime.now().strftime("%Y-%m-%d")
    if user['last_checkin'] == today:
        bot.reply_to(message, f"今日已签到！明日可再次领取 {CHECKIN_REWARD} 积分")
        return
    DBUtils.update_user_points(user_id, CHECKIN_REWARD)
    DBUtils.update_checkin(user_id)
    new_points = user['points'] + CHECKIN_REWARD
    bot.reply_to(message, f"签到成功！\n获得 {CHECKIN_REWARD} 积分\n当前积分：{new_points} 分")

@bot.message_handler(commands=['invite'])
def handle_invite(message):
    user_id = message.from_user.id
    user = DBUtils.get_user(user_id)
    if not user:
        DBUtils.create_or_update_user(user_id, message.from_user.username or "未知用户")
        user = DBUtils.get_user(user_id)
    if user['is_banned']:
        bot.reply_to(message, "账号已封禁")
        return
    bot_username = bot.get_me().username
    invite_link = f"https://t.me/{bot_username}?start={user_id}"
    invite_count = DBUtils.get_invite_count(user_id)
    invite_msg = f"""
👥 邀请好友系统
每成功邀请一位好友，您将获得 {INVITE_REWARD} 积分奖励！
您的专属邀请链接：
<code>{invite_link}</code>
当前已邀请人数：{invite_count} 人
已获得积分：{invite_count * INVITE_REWARD} 分
    """
    bot.reply_to(message, invite_msg, parse_mode='HTML')

@bot.message_handler(commands=['pay'])
def handle_pay(message):
    user_id = message.from_user.id
    user = DBUtils.get_user(user_id)
    if not user:
        DBUtils.create_or_update_user(user_id, message.from_user.username or "未知用户")
        user = DBUtils.get_user(user_id)
    if user['is_banned']:
        bot.reply_to(message, "账号已封禁")
        return
    args = message.text.split()
    if len(args) != 2:
        bot.reply_to(message, "格式错误！\n正确格式：/pay USDT数量\n示例：/pay 10")
        return
    try:
        amount = float(args[1])
        if amount <= 0:
            raise ValueError
    except:
        bot.reply_to(message, "请输入有效的正数！")
        return
    unique_id = f"PAY_{int(time.time())}_{user_id}_{random.randint(1000,9999)}"
    resp = client.pay_link(amount, unique_id)
    if not resp or resp.get('code') != 200:
        bot.reply_to(message, f"创建订单失败：{resp.get('error', '未知错误')}")
        return
    data = resp.get('data', {})
    pay_url = data.get('pay_url', '')
    if not pay_url:
        bot.reply_to(message, "创建订单失败：未返回支付链接")
        return
    diamonds = int(amount * 10)
    orders[unique_id] = {
        'user_id': user_id,
        'amount': amount,
        'status': 'pending',
        'timestamp': time.time()
    }
    keyboard = telebot.types.InlineKeyboardMarkup()
    keyboard.add(telebot.types.InlineKeyboardButton("💰 支付", url=pay_url))
    bot.reply_to(message,
        f"🔰 充值订单已创建\n━━━━━━━━━━━━━━━━━━━━\n金额：{amount} USDT\n获得钻石：{diamonds} 💎\n━━━━━━━━━━━━━━━━━━━━\n点击下方按钮完成支付：",
        reply_markup=keyboard)

@bot.message_handler(commands=['km'])
def handle_km(message):
    user_id = message.from_user.id
    user = DBUtils.get_user(user_id)
    if not user:
        DBUtils.create_or_update_user(user_id, message.from_user.username or "未知用户")
        user = DBUtils.get_user(user_id)
    if user['is_banned']:
        bot.reply_to(message, "账号已封禁")
        return
    args = message.text.split()
    if len(args) != 2:
        bot.reply_to(message, "格式错误！正确格式：/km 卡密")
        return
    card_code = args[1].strip().upper()
    success, points = DBUtils.use_card_code(card_code, user_id)
    if success:
        DBUtils.update_user_points(user_id, points)
        new_points = user['points'] + points
        bot.reply_to(message, f"兑换成功！\n获得 {points} 积分\n当前积分：{new_points} 分")
    else:
        bot.reply_to(message, "卡密无效或已被使用！")

@bot.message_handler(commands=['zs'])
def handle_zs(message):
    user_id = message.from_user.id
    user = DBUtils.get_user(user_id)
    if not user:
        DBUtils.create_or_update_user(user_id, message.from_user.username or "未知用户")
        user = DBUtils.get_user(user_id)
    if user['is_banned']:
        bot.reply_to(message, "账号已封禁")
        return
    args = message.text.split()
    if len(args) != 2:
        bot.reply_to(message, "格式错误！正确格式：/zs 钻石卡密")
        return
    card_code = args[1].strip().upper()
    success, diamonds = DBUtils.use_diamond_card(card_code, user_id)
    if success:
        DBUtils.update_user_diamonds(user_id, diamonds)
        DBUtils.log_diamond_transaction(user_id, 'card_redeem', diamonds, f'兑换钻石卡密')
        new_diamonds = DBUtils.get_user(user_id)['diamonds']
        bot.reply_to(message, f"钻石卡密兑换成功！\n获得 {diamonds} 钻石\n当前钻石：{new_diamonds} 钻")
    else:
        bot.reply_to(message, "钻石卡密无效或已被使用！")

@bot.message_handler(commands=['eys'])
@check_feature_enabled('eys')
def handle_eys(message):
    user_id = message.from_user.id
    user = DBUtils.get_user(user_id)
    if not user:
        DBUtils.create_or_update_user(user_id, message.from_user.username or "未知用户")
        user = DBUtils.get_user(user_id)
    if user['is_banned']:
        bot.reply_to(message, "账号已封禁")
        return
    if not check_channel_membership(user_id):
        send_channel_required_message(message.chat.id)
        return
    args = message.text.split()
    if len(args) != 3:
        bot.reply_to(message, "格式错误！\n正确格式：/eys 姓名 身份证\n消耗：1积分")
        return
    name, sfz = args[1].strip(), args[2].strip().upper()
    if len(sfz) != 18 or not (sfz[:-1].isdigit() and (sfz[-1].isdigit() or sfz[-1] == 'X')):
        bot.reply_to(message, "身份证格式错误！必须为18位（最后一位可带X）")
        return
    if not user['is_authorized'] and user['points'] < 1:
        bot.reply_to(message, f"积分不足！需要1积分，当前 {user['points']} 分")
        return
    if not user['is_authorized']:
        DBUtils.update_user_points(user_id, -1)
        remaining = user['points'] - 1
    else:
        remaining = user['points']
    keyboard = telebot.types.InlineKeyboardMarkup(row_width=2)
    keyboard.add(
        telebot.types.InlineKeyboardButton("接口1", callback_data=f"eys_1_{user_id}_{name}_{sfz}"),
        telebot.types.InlineKeyboardButton("接口2", callback_data=f"eys_2_{user_id}_{name}_{sfz}")
    )
    bot.reply_to(message, "请选择核验接口：", reply_markup=keyboard)

@bot.message_handler(commands=['sys'])
@check_feature_enabled('sys')
def handle_sys(message):
    user_id = message.from_user.id
    user = DBUtils.get_user(user_id)
    if not user:
        DBUtils.create_or_update_user(user_id, message.from_user.username or "未知用户")
        user = DBUtils.get_user(user_id)
    if user['is_banned']:
        bot.reply_to(message, "账号已封禁")
        return
    if not check_channel_membership(user_id):
        send_channel_required_message(message.chat.id)
        return
    args = message.text.split()
    if len(args) != 4:
        bot.reply_to(message, "格式错误！\n正确格式：/sys 姓名 手机号 身份证\n消耗：3积分")
        return
    name, phone, idcard = args[1].strip(), args[2].strip(), args[3].strip().upper()
    if len(idcard) != 18 or not (idcard[:-1].isdigit() and (idcard[-1].isdigit() or idcard[-1] == 'X')):
        bot.reply_to(message, "身份证格式错误！必须为18位（最后一位可带X）")
        return
    if not re.match(r'^1[3-9]\d{9}$', phone):
        bot.reply_to(message, "手机号格式错误！请输入11位正确手机号")
        return
    if not user['is_authorized'] and user['points'] < 3:
        bot.reply_to(message, f"积分不足！需要3积分，当前 {user['points']} 分")
        return
    if not user['is_authorized']:
        DBUtils.update_user_points(user_id, -3)
        remaining = user['points'] - 3
    else:
        remaining = user['points']
    msg = bot.reply_to(message, f"正在三要素核验...\n姓名：{name}\n手机号：{phone}\n身份证：{idcard}")
    try:
        result = query_sys(name, phone, idcard)
        content = f"姓名：{name}\n手机号：{phone}\n身份证：{idcard}\n\n结果：{result}"
        title = "三要素核验结果"
        full_result = create_collapsible_text(title, content, f"剩余积分：{remaining}")
        bot.edit_message_text(full_result, user_id, msg.message_id, parse_mode='HTML')
    except Exception as e:
        if not user['is_authorized']:
            DBUtils.update_user_points(user_id, 3)
        bot.edit_message_text(f"核验失败：{str(e)}\n已返还积分", user_id, msg.message_id)

@bot.message_handler(commands=['face'])
@check_feature_enabled('face')
def handle_face(message):
    user_id = message.from_user.id
    user = DBUtils.get_user(user_id)
    if not user:
        DBUtils.create_or_update_user(user_id, message.from_user.username or "未知用户")
        user = DBUtils.get_user(user_id)
    if user['is_banned']:
        bot.reply_to(message, "账号已封禁")
        return
    if not check_channel_membership(user_id):
        send_channel_required_message(message.chat.id)
        return
    if not user['is_authorized'] and user['points'] < 3:
        bot.reply_to(message, f"积分不足！\n人脸核验需 3 积分，当前剩余 {user['points']} 分")
        return
    face_user_data[user_id] = {'step': 'name'}
    bot.reply_to(message, "人脸核验\n\n消耗：3积分/次\n\n请输入姓名：")


@bot.message_handler(func=lambda m: m.from_user.id in face_user_data and face_user_data.get(m.from_user.id, {}).get('step') == 'name')
def face_handle_name(message):
    user_id = message.from_user.id
    name = message.text.strip()
    if not name:
        bot.reply_to(message, "姓名不能为空，请重新输入：")
        return
    face_user_data[user_id]['name'] = name
    face_user_data[user_id]['step'] = 'id_card'
    bot.reply_to(message, f"姓名：{name}\n\n请输入身份证号：")


@bot.message_handler(func=lambda m: m.from_user.id in face_user_data and face_user_data.get(m.from_user.id, {}).get('step') == 'id_card')
def face_handle_id_card(message):
    user_id = message.from_user.id
    id_card = message.text.strip().upper()
    if len(id_card) != 18 or not (id_card[:-1].isdigit() and (id_card[-1].isdigit() or id_card[-1] == 'X')):
        bot.reply_to(message, "身份证号格式错误！必须为18位（最后一位可带X）")
        return
    face_user_data[user_id]['id_card'] = id_card
    face_user_data[user_id]['step'] = 'photo'
    bot.reply_to(message, f"姓名：{face_user_data[user_id]['name']}\n身份证：{id_card}\n\n请发送一张带有人脸的照片：")


@bot.message_handler(content_types=['photo'], func=lambda m: m.from_user.id in face_user_data and face_user_data.get(m.from_user.id, {}).get('step') == 'photo')
def face_handle_photo(message):
    user_id = message.from_user.id
    user = DBUtils.get_user(user_id)
    try:
        file_info = bot.get_file(message.photo[-1].file_id)
        downloaded_file = bot.download_file(file_info.file_path)
        os.makedirs("face_images", exist_ok=True)
        img_path = f"face_images/{user_id}_{int(time.time())}.jpg"
        with open(img_path, 'wb') as f:
            f.write(downloaded_file)
        name = face_user_data[user_id]['name']
        id_card = face_user_data[user_id]['id_card']
        if not user['is_authorized']:
            DBUtils.update_user_points(user_id, -3)
            remaining = user['points'] - 3
        else:
            remaining = user['points']
        processing_msg = bot.reply_to(message, "正在进行人脸核验，请稍候...")
        result = face_verify(name, id_card, img_path)
        os.remove(img_path)
        del face_user_data[user_id]
        if result.get('code') == 200 or result.get('data') == '实名人证验证通过':
            content = f"姓名：{name}\n身份证：{id_card}\n\n结果：实名人证验证通过"
            title = "人脸核验结果"
            full_result = create_collapsible_text(title, content, f"剩余积分：{remaining}")
            bot.edit_message_text(full_result, chat_id=user_id, message_id=processing_msg.message_id, parse_mode='HTML')
        else:
            error_msg = result.get('msg', '验证失败')
            content = f"姓名：{name}\n身份证：{id_card}\n\n结果：{error_msg}"
            title = "人脸核验结果"
            full_result = create_collapsible_text(title, content, f"剩余积分：{remaining}")
            bot.edit_message_text(full_result, chat_id=user_id, message_id=processing_msg.message_id, parse_mode='HTML')
    except Exception as e:
        bot.reply_to(message, f"处理失败：{str(e)}")
        if user_id in face_user_data:
            del face_user_data[user_id]

@bot.message_handler(commands=['yhk'])
@check_feature_enabled('yhk')
def handle_yhk(message):
    user_id = message.from_user.id
    user = DBUtils.get_user(user_id)
    if not user:
        DBUtils.create_or_update_user(user_id, message.from_user.username or "未知用户")
        user = DBUtils.get_user(user_id)
    if user['is_banned']:
        bot.reply_to(message, "账号已封禁")
        return
    if not check_channel_membership(user_id):
        send_channel_required_message(message.chat.id)
        return
    args = message.text.split()
    if len(args) != 2:
        bot.reply_to(message, "格式错误！\n正确格式：/yhk 银行卡号\n消耗：1积分")
        return
    bank_card = args[1].strip()
    if not bank_card.isdigit() or len(bank_card) < 16:
        bot.reply_to(message, "银行卡号格式错误！请输入有效的银行卡号")
        return
    if not user['is_authorized'] and user['points'] < 1:
        bot.reply_to(message, f"积分不足！需要1积分，当前 {user['points']} 分")
        return
    if not user['is_authorized']:
        DBUtils.update_user_points(user_id, -1)
        remaining = user['points'] - 1
    else:
        remaining = user['points']
    msg = bot.reply_to(message, f"正在查询银行卡归属地...\n银行卡：{bank_card}")
    try:
        result = query_yhk(bank_card)
        content = f"银行卡号：{bank_card}\n\n{result}"
        title = "银行卡归属地查询结果"
        full_result = create_collapsible_text(title, content, f"剩余积分：{remaining}")
        bot.edit_message_text(full_result, user_id, msg.message_id, parse_mode='HTML')
    except Exception as e:
        if not user['is_authorized']:
            DBUtils.update_user_points(user_id, 1)
        bot.edit_message_text(f"查询失败：{str(e)}", user_id, msg.message_id)

@bot.message_handler(commands=['k3'])
@check_feature_enabled('k3')
def handle_k3(message):
    user_id = message.from_user.id
    user = DBUtils.get_user(user_id)
    if not user:
        DBUtils.create_or_update_user(user_id, message.from_user.username or "未知用户")
        user = DBUtils.get_user(user_id)
    if user['is_banned']:
        bot.reply_to(message, "账号已封禁")
        return
    if not check_channel_membership(user_id):
        send_channel_required_message(message.chat.id)
        return
    args = message.text.split()
    if len(args) != 4:
        bot.reply_to(message, "格式错误！\n正确格式：/k3 姓名 身份证 银行卡\n消耗：2积分")
        return
    name, id_card, bank_card = args[1].strip(), args[2].strip().upper(), args[3].strip()
    if len(id_card) != 18 or not (id_card[:-1].isdigit() and (id_card[-1].isdigit() or id_card[-1] == 'X')):
        bot.reply_to(message, "身份证格式错误！必须为18位（最后一位可带X）")
        return
    if not bank_card.isdigit() or len(bank_card) < 16:
        bot.reply_to(message, "银行卡号格式错误！请输入有效的银行卡号")
        return
    if not user['is_authorized'] and user['points'] < 2:
        bot.reply_to(message, f"积分不足！需要2积分，当前 {user['points']} 分")
        return
    if not user['is_authorized']:
        DBUtils.update_user_points(user_id, -2)
        remaining = user['points'] - 2
    else:
        remaining = user['points']
    msg = bot.reply_to(message, f"正在核验银行卡三要素...\n姓名：{name}\n身份证：{id_card}\n银行卡：{bank_card[-4:]}")
    try:
        result = query_k3(name, id_card, bank_card)
        content = f"姓名：{name}\n身份证：{id_card}\n银行卡：{bank_card}\n\n结果：{result}"
        title = "银行卡三要素核验结果"
        full_result = create_collapsible_text(title, content, f"剩余积分：{remaining}")
        bot.edit_message_text(full_result, user_id, msg.message_id, parse_mode='HTML')
    except Exception as e:
        if not user['is_authorized']:
            DBUtils.update_user_points(user_id, 2)
        bot.edit_message_text(f"核验失败：{str(e)}", user_id, msg.message_id)

@bot.message_handler(commands=['k4'])
@check_feature_enabled('k4')
def handle_k4(message):
    user_id = message.from_user.id
    user = DBUtils.get_user(user_id)
    if not user:
        DBUtils.create_or_update_user(user_id, message.from_user.username or "未知用户")
        user = DBUtils.get_user(user_id)
    if user['is_banned']:
        bot.reply_to(message, "账号已封禁")
        return
    if not check_channel_membership(user_id):
        send_channel_required_message(message.chat.id)
        return
    args = message.text.split()
    if len(args) != 5:
        bot.reply_to(message, "格式错误！\n正确格式：/k4 姓名 身份证 手机 银行卡\n消耗：2积分")
        return
    name, id_card, phone, bank_card = args[1].strip(), args[2].strip().upper(), args[3].strip(), args[4].strip()
    if len(id_card) != 18 or not (id_card[:-1].isdigit() and (id_card[-1].isdigit() or id_card[-1] == 'X')):
        bot.reply_to(message, "身份证格式错误！必须为18位（最后一位可带X）")
        return
    if not re.match(r'^1[3-9]\d{9}$', phone):
        bot.reply_to(message, "手机号格式错误！请输入11位正确手机号")
        return
    if not bank_card.isdigit() or len(bank_card) < 16:
        bot.reply_to(message, "银行卡号格式错误！请输入有效的银行卡号")
        return
    if not user['is_authorized'] and user['points'] < 2:
        bot.reply_to(message, f"积分不足！需要2积分，当前 {user['points']} 分")
        return
    if not user['is_authorized']:
        DBUtils.update_user_points(user_id, -2)
        remaining = user['points'] - 2
    else:
        remaining = user['points']
    msg = bot.reply_to(message, f"正在核验银行卡四要素...\n姓名：{name}\n身份证：{id_card}\n手机：{phone}\n银行卡：{bank_card[-4:]}")
    try:
        result = query_k4(name, id_card, phone, bank_card)
        content = f"姓名：{name}\n身份证：{id_card}\n手机：{phone}\n银行卡：{bank_card}\n\n结果：{result}"
        title = "银行卡四要素核验结果"
        full_result = create_collapsible_text(title, content, f"剩余积分：{remaining}")
        bot.edit_message_text(full_result, user_id, msg.message_id, parse_mode='HTML')
    except Exception as e:
        if not user['is_authorized']:
            DBUtils.update_user_points(user_id, 2)
        bot.edit_message_text(f"核验失败：{str(e)}", user_id, msg.message_id)

@bot.message_handler(commands=['id_extract'])
@check_feature_enabled('id_extract')
def handle_id_extract(message):
    user_id = message.from_user.id
    user = DBUtils.get_user(user_id)
    if not user:
        DBUtils.create_or_update_user(user_id, message.from_user.username or "未知用户")
        user = DBUtils.get_user(user_id)
    if user['is_banned']:
        bot.reply_to(message, "账号已封禁")
        return
    if not check_channel_membership(user_id):
        send_channel_required_message(message.chat.id)
        return
    if not user['is_authorized'] and user['points'] < 1:
        bot.reply_to(message, f"积分不足！需要1积分，当前 {user['points']} 分")
        return
    user_states[user_id] = {'waiting_id_file': True}
    bot.reply_to(message, "请上传包含身份证号的TXT文件\n消耗：1积分/次")

# ==================== 钻石消耗命令 ====================
@bot.message_handler(commands=['man'])
@check_feature_enabled('man')
def handle_man(message):
    user_id = message.from_user.id
    user = DBUtils.get_user(user_id)
    if not user:
        DBUtils.create_or_update_user(user_id, message.from_user.username or "未知用户")
        user = DBUtils.get_user(user_id)
    if user['is_banned']:
        bot.reply_to(message, "账号已封禁")
        return
    if not check_channel_membership(user_id):
        send_channel_required_message(message.chat.id)
        return
    args = message.text.split()
    if len(args) != 3:
        bot.reply_to(message, f"格式错误！\n正确格式：/man 姓名 身份证\n消耗：{DBUtils.get_user_service_price(user_id, 'man')} 💎")
        return
    name, id_card = args[1].strip(), args[2].strip().upper()
    if len(id_card) != 18 or not (id_card[:-1].isdigit() and (id_card[-1].isdigit() or id_card[-1] == 'X')):
        bot.reply_to(message, "身份证格式错误！必须为18位（最后一位可带X）")
        return
    price = DBUtils.get_user_service_price(user_id, 'man')
    if user['diamonds'] < price:
        bot.reply_to(message, f"钻石不足！需要 {price} 钻石，当前 {user['diamonds']} 钻")
        return
    DBUtils.update_user_diamonds(user_id, -price)
    DBUtils.log_diamond_transaction(user_id, 'consume', -price, f'慢线假地址订单', '')
    order_no = DBUtils.create_order(user_id, 'man', {'name': name, 'id_card': id_card}, price)
    bot.reply_to(message,
        f"✅ 订单已提交\n━━━━━━━━━━━━━━━━━━━━\n订单号：{order_no}\n服务：慢线假地址\n内容：姓名:{name} | 身份证:{id_card}\n消耗：{price} 💎\n━━━━━━━━━━━━━━━━━━━━\n⏳ 请等待管理员处理...")
    logger.info(f"用户 {user_id} 提交慢线假地址订单: {order_no}")

@bot.message_handler(commands=['dy'])
@check_feature_enabled('dy')
def handle_dy(message):
    user_id = message.from_user.id
    user = DBUtils.get_user(user_id)
    if not user:
        DBUtils.create_or_update_user(user_id, message.from_user.username or "未知用户")
        user = DBUtils.get_user(user_id)
    if user['is_banned']:
        bot.reply_to(message, "账号已封禁")
        return
    if not check_channel_membership(user_id):
        send_channel_required_message(message.chat.id)
        return
    args = message.text.split()
    if len(args) != 2:
        bot.reply_to(message, f"格式错误！\n正确格式：/dy 抖音号\n消耗：{DBUtils.get_user_service_price(user_id, 'dy')} 💎")
        return
    dy_id = args[1].strip()
    if not dy_id:
        bot.reply_to(message, "抖音号不能为空！")
        return
    price = DBUtils.get_user_service_price(user_id, 'dy')
    if user['diamonds'] < price:
        bot.reply_to(message, f"钻石不足！需要 {price} 钻石，当前 {user['diamonds']} 钻")
        return
    DBUtils.update_user_diamonds(user_id, -price)
    DBUtils.log_diamond_transaction(user_id, 'consume', -price, f'抖音反订单', '')
    order_no = DBUtils.create_order(user_id, 'dy', {'dy_id': dy_id}, price)
    bot.reply_to(message,
        f"✅ 订单已提交\n━━━━━━━━━━━━━━━━━━━━\n订单号：{order_no}\n服务：抖音反\n内容：抖音号:{dy_id}\n消耗：{price} 💎\n━━━━━━━━━━━━━━━━━━━━\n⏳ 请等待管理员处理...")
    logger.info(f"用户 {user_id} 提交抖音反订单: {order_no}")

# ==================== 拼接真地址（钻石订单） ====================
@bot.message_handler(commands=['zhend'])
@check_feature_enabled('zhend')
def handle_zhend(message):
    user_id = message.from_user.id
    user = DBUtils.get_user(user_id)
    if not user:
        DBUtils.create_or_update_user(user_id, message.from_user.username or "未知用户")
        user = DBUtils.get_user(user_id)
    if user['is_banned']:
        bot.reply_to(message, "账号已封禁")
        return
    if not check_channel_membership(user_id):
        send_channel_required_message(message.chat.id)
        return
    args = message.text.split()
    if len(args) != 3:
        bot.reply_to(message, f"格式错误！\n正确格式：/zhend 姓名 身份证\n消耗：{DBUtils.get_user_service_price(user_id, 'zhend')} 💎\n\n{ORDER_NOTICE}")
        return
    name, id_card = args[1].strip(), args[2].strip().upper()
    if len(id_card) != 18 or not (id_card[:-1].isdigit() and (id_card[-1].isdigit() or id_card[-1] == 'X')):
        bot.reply_to(message, "身份证格式错误！必须为18位（最后一位可带X）")
        return
    price = DBUtils.get_user_service_price(user_id, 'zhend')
    if user['diamonds'] < price:
        bot.reply_to(message, f"钻石不足！需要 {price} 钻石，当前 {user['diamonds']} 钻")
        return
    DBUtils.update_user_diamonds(user_id, -price)
    DBUtils.log_diamond_transaction(user_id, 'consume', -price, f'拼接真地址订单', '')
    order_no = DBUtils.create_order(user_id, 'zhend', {'name': name, 'id_card': id_card}, price)
    bot.reply_to(message,
        f"✅ 订单已提交\n━━━━━━━━━━━━━━━━━━━━\n订单号：{order_no}\n服务：拼接真地址\n内容：姓名:{name} | 身份证:{id_card}\n消耗：{price} 💎\n━━━━━━━━━━━━━━━━━━━━\n⏳ 请等待管理员处理...\n\n{ORDER_NOTICE}")
    logger.info(f"用户 {user_id} 提交拼接真地址订单: {order_no}")

# ==================== 大库户籍地（钻石订单） ====================
@bot.message_handler(commands=['dk'])
@check_feature_enabled('dk')
def handle_dk(message):
    user_id = message.from_user.id
    user = DBUtils.get_user(user_id)
    if not user:
        DBUtils.create_or_update_user(user_id, message.from_user.username or "未知用户")
        user = DBUtils.get_user(user_id)
    if user['is_banned']:
        bot.reply_to(message, "账号已封禁")
        return
    if not check_channel_membership(user_id):
        send_channel_required_message(message.chat.id)
        return
    args = message.text.split()
    if len(args) != 3:
        bot.reply_to(message, f"格式错误！\n正确格式：/dk 姓名 身份证\n消耗：{DBUtils.get_user_service_price(user_id, 'dk')} 💎\n\n{ORDER_NOTICE}")
        return
    name, id_card = args[1].strip(), args[2].strip().upper()
    if len(id_card) != 18 or not (id_card[:-1].isdigit() and (id_card[-1].isdigit() or id_card[-1] == 'X')):
        bot.reply_to(message, "身份证格式错误！必须为18位（最后一位可带X）")
        return
    price = DBUtils.get_user_service_price(user_id, 'dk')
    if user['diamonds'] < price:
        bot.reply_to(message, f"钻石不足！需要 {price} 钻石，当前 {user['diamonds']} 钻")
        return
    DBUtils.update_user_diamonds(user_id, -price)
    DBUtils.log_diamond_transaction(user_id, 'consume', -price, f'大库户籍地订单', '')
    order_no = DBUtils.create_order(user_id, 'dk', {'name': name, 'id_card': id_card}, price)
    bot.reply_to(message,
        f"✅ 订单已提交\n━━━━━━━━━━━━━━━━━━━━\n订单号：{order_no}\n服务：大库户籍地\n内容：姓名:{name} | 身份证:{id_card}\n消耗：{price} 💎\n━━━━━━━━━━━━━━━━━━━━\n⏳ 请等待管理员处理...\n\n{ORDER_NOTICE}")
    logger.info(f"用户 {user_id} 提交大库户籍地订单: {order_no}")

# ==================== 用户查询价格 ====================
@bot.message_handler(commands=['prices'])
def handle_prices(message):
    user_id = message.from_user.id
    user = DBUtils.get_user(user_id)
    if not user:
        DBUtils.create_or_update_user(user_id, message.from_user.username or "未知用户")
        user = DBUtils.get_user(user_id)
    text = "💎 当前业务价格\n━━━━━━━━━━━━━━━━━━━━\n"
    for svc in ['man', 'dy', 'zhend', 'dk', 'mxh']:
        if not DBUtils.is_feature_enabled(svc):
            continue
        price = DBUtils.get_user_service_price(user_id, svc)
        label = get_service_label(svc)
        text += f"/{svc} {label}：{price} 💎\n"
    text += "━━━━━━━━━━━━━━━━━━━━"
    bot.reply_to(message, text)

# ==================== 名下号（钻石订单） ====================
@bot.message_handler(commands=['mxh'])
@check_feature_enabled('mxh')
def handle_mxh(message):
    user_id = message.from_user.id
    user = DBUtils.get_user(user_id)
    if not user:
        DBUtils.create_or_update_user(user_id, message.from_user.username or "未知用户")
        user = DBUtils.get_user(user_id)
    if user['is_banned']:
        bot.reply_to(message, "账号已封禁")
        return
    if not check_channel_membership(user_id):
        send_channel_required_message(message.chat.id)
        return
    args = message.text.split()
    if len(args) != 3:
        bot.reply_to(message, f"格式错误！\n正确格式：/mxh 姓名 身份证\n消耗：{DBUtils.get_user_service_price(user_id, 'mxh')} 💎")
        return
    name, id_card = args[1].strip(), args[2].strip().upper()
    if len(id_card) != 18 or not (id_card[:-1].isdigit() and (id_card[-1].isdigit() or id_card[-1] == 'X')):
        bot.reply_to(message, "身份证格式错误！必须为18位（最后一位可带X）")
        return
    price = DBUtils.get_user_service_price(user_id, 'mxh')
    if user['diamonds'] < price:
        bot.reply_to(message, f"钻石不足！需要 {price} 钻石，当前 {user['diamonds']} 钻")
        return
    DBUtils.update_user_diamonds(user_id, -price)
    DBUtils.log_diamond_transaction(user_id, 'consume', -price, f'名下号订单', '')
    order_no = DBUtils.create_order(user_id, 'mxh', {'name': name, 'id_card': id_card}, price)
    bot.reply_to(message,
        f"✅ 订单已提交\n━━━━━━━━━━━━━━━━━━━━\n订单号：{order_no}\n服务：名下号\n内容：姓名:{name} | 身份证:{id_card}\n消耗：{price} 💎\n━━━━━━━━━━━━━━━━━━━━\n⏳ 请等待管理员处理...")
    logger.info(f"用户 {user_id} 提交名下号订单: {order_no}")

# ==================== admin 命令 ====================
@bot.message_handler(commands=['admin'])
def handle_admin(message):
    user_id = message.from_user.id
    if user_id not in ADMIN_IDS:
        bot.reply_to(message, "无权限操作！")
        return
    pending_count = DBUtils.get_pending_order_count()
    all_users = DBUtils.get_all_users()
    total_users = len(all_users)
    total_points = sum(u[2] for u in all_users)
    total_diamonds = sum(u[3] for u in all_users)
    admin_text = f"""
👑 管理员面板
━━━━━━━━━━━━━━━━━━━━
📊 系统统计
• 用户总数：{total_users}
• 待处理订单：{pending_count}
• 总积分：{total_points}
• 总钻石：{total_diamonds}
━━━━━━━━━━━━━━━━━━━━
请选择操作：
    """
    bot.reply_to(message, admin_text, reply_markup=build_admin_keyboard())

@bot.message_handler(commands=['admin_card'])
def admin_gen_card(message):
    user_id = message.from_user.id
    if user_id not in ADMIN_IDS:
        return
    try:
        args = message.text.split()
        if len(args) != 3:
            bot.reply_to(message, "格式错误！\n正确格式：/admin_card 积分 张数\n示例：/admin_card 10 5")
            return
        points = int(args[1])
        count = int(args[2])
        if points <= 0 or count <= 0:
            bot.reply_to(message, "积分和张数必须大于0！")
            return
        cards = DBUtils.generate_card_code(points, count)
        text = f"✅ 生成 {count} 张 {points} 积分卡密：\n━━━━━━━━━━━━━━━━━━━━\n"
        for code, p in cards:
            text += f"`{code}`\n"
        bot.reply_to(message, text, parse_mode='Markdown')
    except:
        bot.reply_to(message, "格式错误！\n正确格式：/admin_card 积分 张数")

@bot.message_handler(commands=['admin_dcard'])
def admin_gen_dcard(message):
    user_id = message.from_user.id
    if user_id not in ADMIN_IDS:
        return
    try:
        args = message.text.split()
        if len(args) != 3:
            bot.reply_to(message, "格式错误！\n正确格式：/admin_dcard 钻石 张数\n示例：/admin_dcard 10 5")
            return
        diamonds = int(args[1])
        count = int(args[2])
        if diamonds <= 0 or count <= 0:
            bot.reply_to(message, "钻石和张数必须大于0！")
            return
        cards = DBUtils.generate_diamond_card(diamonds, count)
        text = f"✅ 生成 {count} 张 {diamonds} 钻石卡密：\n━━━━━━━━━━━━━━━━━━━━\n"
        for code, d in cards:
            text += f"`{code}`\n"
        bot.reply_to(message, text, parse_mode='Markdown')
    except:
        bot.reply_to(message, "格式错误！\n正确格式：/admin_dcard 钻石 张数")

# ==================== 统一消息处理器（处理所有非命令消息） ====================
@bot.message_handler(func=lambda message: True)
def handle_all_messages(message):
    user_id = message.from_user.id
    
    if message.text and message.text.startswith('/'):
        return
    
    # 管理员回单处理（放在最前面，优先级最高）
    if user_id in ADMIN_IDS and message.reply_to_message:
        reply_text = message.reply_to_message.text or message.reply_to_message.caption or ""
        user_id_match = re.search(r'用户ID：(\d+)', reply_text)
        order_no_match = re.search(r'(?:订单号|处理订单|退费)：([A-Z0-9]+)', reply_text)
        if user_id_match and order_no_match:
            target_user_id = int(user_id_match.group(1))
            order_no = order_no_match.group(1)
            # 判断是否为部分退费回单（订单已取消，只需转发内容给用户）
            order = DBUtils.get_order_by_no(order_no)
            is_refund_reply = '退费' in reply_text
            try:
                if message.photo:
                    file_id = message.photo[-1].file_id
                    if not is_refund_reply and order and order['status'] == 'pending':
                        DBUtils.complete_order(order_no, file_id, 'photo')
                        bot.send_message(target_user_id,
                            f"📨 您的订单已处理完成！\n━━━━━━━━━━━━━━━━━━━━\n订单号：{order_no}\n服务：{get_service_label(order['service_name'])}\n状态：✅ 已完成\n━━━━━━━━━━━━━━━━━━━━")
                    bot.send_photo(target_user_id, file_id)
                    bot.reply_to(message, f"✅ 回单已发送给用户 {target_user_id}")
                elif message.text:
                    if not is_refund_reply and order and order['status'] == 'pending':
                        DBUtils.complete_order(order_no, message.text.strip(), 'text')
                        bot.send_message(target_user_id,
                            f"📨 您的订单已处理完成！\n━━━━━━━━━━━━━━━━━━━━\n订单号：{order_no}\n服务：{get_service_label(order['service_name'])}\n状态：✅ 已完成\n━━━━━━━━━━━━━━━━━━━━\n回单内容：\n{message.text.strip()}")
                    else:
                        bot.send_message(target_user_id, f"📨 订单 {order_no} 部分退费回单：\n{message.text.strip()}")
                    bot.reply_to(message, f"✅ 回单已发送给用户 {target_user_id}")
                elif message.document:
                    file_id = message.document.file_id
                    if not is_refund_reply and order and order['status'] == 'pending':
                        DBUtils.complete_order(order_no, file_id, 'document')
                        bot.send_message(target_user_id,
                            f"📨 您的订单已处理完成！\n━━━━━━━━━━━━━━━━━━━━\n订单号：{order_no}\n服务：{get_service_label(order['service_name'])}\n状态：✅ 已完成")
                    bot.send_document(target_user_id, file_id)
                    bot.reply_to(message, f"✅ 回单已发送给用户 {target_user_id}")
                return
            except Exception as e:
                logger.error(f"管理员回单处理失败，订单号：{order_no}，错误：{e}", exc_info=True)
                bot.reply_to(message, f"❌ 回单处理失败：{str(e)}")
                return
    

    
    # 身份证提取 - 接收文件
    if message.document and user_id in user_states and user_states.get(user_id, {}).get('waiting_id_file'):
        if not message.document.file_name.lower().endswith('.txt'):
            bot.reply_to(message, "请上传TXT格式的文件！")
            return
        user = DBUtils.get_user(user_id)
        if not user['is_authorized'] and user['points'] < 1:
            bot.reply_to(message, f"积分不足！需要1积分")
            return
        msg = bot.reply_to(message, "正在处理文件...")
        try:
            file_info = bot.get_file(message.document.file_id)
            downloaded_file = bot.download_file(file_info.file_path)
            file_content = downloaded_file.decode('utf-8', errors='ignore')
            id_cards = extract_id_cards_from_text(file_content)
            if not id_cards:
                bot.edit_message_text("未找到有效的18位身份证号码", user_id, msg.message_id)
                return
            if not user['is_authorized']:
                DBUtils.update_user_points(user_id, -1)
                remaining = user['points'] - 1
            else:
                remaining = user['points']
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            filename = f"id_cards_{timestamp}.txt"
            with open(filename, 'w', encoding='utf-8') as f:
                f.write(f"身份证号码提取结果\n生成时间：{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
                f.write(f"提取数量：{len(id_cards)}个\n{'='*50}\n\n")
                for id_card in id_cards:
                    f.write(f"{id_card}\n")
            with open(filename, 'rb') as f:
                bot.send_document(user_id, f, caption=f"✅ 提取完成！共 {len(id_cards)} 个身份证\n剩余积分：{remaining}")
            os.remove(filename)
            bot.delete_message(user_id, msg.message_id)
        except Exception as e:
            bot.edit_message_text(f"处理失败：{str(e)}", user_id, msg.message_id)
        del user_states[user_id]
        return

# ==================== 回调处理器 ====================
@bot.callback_query_handler(func=lambda call: call.data == "check_joined")
def check_joined_callback(call):
    user_id = call.from_user.id
    if check_channel_membership(user_id):
        bot.answer_callback_query(call.id, "验证成功！")
        send_welcome(call.message)
    else:
        bot.answer_callback_query(call.id, "请先加入频道！", show_alert=True)

@bot.callback_query_handler(func=lambda call: call.data.startswith("eys_"))
def handle_eys_callback(call):
    _, api, user_id, name, sfz = call.data.split('_', 4)
    user_id = int(user_id)
    if call.from_user.id != user_id:
        bot.answer_callback_query(call.id, "无权限操作！", show_alert=True)
        return
    user = DBUtils.get_user(user_id)
    remaining = user['points'] if user else 0
    msg = bot.send_message(user_id, "正在核验中...")
    if api == '1':
        result = query_eys_v1(name, sfz)
        api_name = "接口1"
    else:
        result = query_eys_v2(name, sfz)
        api_name = "接口2"
    content = f"姓名：{name}\n身份证：{sfz}\n\n结果：{result}"
    title = f"二要素核验结果（{api_name}）"
    full_result = create_collapsible_text(title, content, f"剩余积分：{remaining}")
    bot.edit_message_text(full_result, user_id, msg.message_id, parse_mode='HTML')
    bot.answer_callback_query(call.id)

@bot.callback_query_handler(func=lambda call: call.data.startswith("admin_"))
def handle_admin_callback(call):
    if call.from_user.id not in ADMIN_IDS:
        bot.answer_callback_query(call.id, "无权限操作！", show_alert=True)
        return
    action = call.data.replace("admin_", "")
    if action == "users":
        show_user_list_page(call, 0)
    elif action == "points":
        bot.edit_message_text("💰 积分管理\n━━━━━━━━━━━━━━━━━━━━\n请输入用户ID和积分数量：\n格式：用户ID 积分\n示例：123456 100", call.message.chat.id, call.message.message_id, reply_markup=telebot.types.InlineKeyboardMarkup().add(telebot.types.InlineKeyboardButton("🔙 返回", callback_data="back_admin")))
        bot.register_next_step_handler(call.message, admin_points_handler)
    elif action == "diamonds":
        bot.edit_message_text("💎 钻石管理\n━━━━━━━━━━━━━━━━━━━━\n请输入用户ID和钻石数量：\n格式：用户ID 钻石\n示例：123456 50", call.message.chat.id, call.message.message_id, reply_markup=telebot.types.InlineKeyboardMarkup().add(telebot.types.InlineKeyboardButton("🔙 返回", callback_data="back_admin")))
        bot.register_next_step_handler(call.message, admin_diamonds_handler)
    elif action == "price":
        bot.edit_message_text("⚙️ 价格管理\n━━━━━━━━━━━━━━━━━━━━", call.message.chat.id, call.message.message_id, reply_markup=build_price_keyboard())
    elif action == "card":
        bot.edit_message_text("🎫 卡密系统\n━━━━━━━━━━━━━━━━━━━━\n请选择操作：\n\n生成积分卡密：/admin_card 积分 张数\n生成钻石卡密：/admin_dcard 钻石 张数\n\n示例：\n/admin_card 10 5\n/admin_dcard 20 3", call.message.chat.id, call.message.message_id, reply_markup=telebot.types.InlineKeyboardMarkup().add(telebot.types.InlineKeyboardButton("🔙 返回", callback_data="back_admin")))
    elif action == "orders":
        orders_list = DBUtils.get_pending_orders()
        if not orders_list:
            bot.edit_message_text("📋 暂无待处理订单", call.message.chat.id, call.message.message_id, reply_markup=telebot.types.InlineKeyboardMarkup().add(telebot.types.InlineKeyboardButton("🔙 返回", callback_data="back_admin")))
            return
        bot.edit_message_text("📋 待处理订单\n━━━━━━━━━━━━━━━━━━━━", call.message.chat.id, call.message.message_id, reply_markup=build_order_list_keyboard(orders_list, 0))
    elif action == "broadcast":
        bot.edit_message_text("📢 广播消息\n━━━━━━━━━━━━━━━━━━━━\n请发送要广播的内容（文字/图片/文件）", call.message.chat.id, call.message.message_id, reply_markup=telebot.types.InlineKeyboardMarkup().add(telebot.types.InlineKeyboardButton("🔙 返回", callback_data="back_admin")))
        bot.register_next_step_handler(call.message, admin_broadcast_handler)
    elif action == "stats":
        all_users = DBUtils.get_all_users()
        pending = DBUtils.get_pending_order_count()
        total_users = len(all_users)
        total_points = sum(u[2] for u in all_users)
        total_diamonds = sum(u[3] for u in all_users)
        authorized = sum(1 for u in all_users if u[4])
        banned = sum(1 for u in all_users if u[5])
        text = f"📊 系统统计\n━━━━━━━━━━━━━━━━━━━━\n用户总数：{total_users}\n已授权：{authorized}\n已封禁：{banned}\n总积分：{total_points}\n总钻石：{total_diamonds}\n待处理订单：{pending}\n━━━━━━━━━━━━━━━━━━━━"
        bot.edit_message_text(text, call.message.chat.id, call.message.message_id, reply_markup=telebot.types.InlineKeyboardMarkup().add(telebot.types.InlineKeyboardButton("🔙 返回", callback_data="back_admin")))
    elif action == "ban":
        bot.edit_message_text("❌ 封禁用户\n━━━━━━━━━━━━━━━━━━━━\n请输入要封禁的用户ID：", call.message.chat.id, call.message.message_id, reply_markup=telebot.types.InlineKeyboardMarkup().add(telebot.types.InlineKeyboardButton("🔙 返回", callback_data="back_admin")))
        bot.register_next_step_handler(call.message, admin_ban_handler)
    elif action == "unban":
        bot.edit_message_text("✅ 解封用户\n━━━━━━━━━━━━━━━━━━━━\n请输入要解封的用户ID：", call.message.chat.id, call.message.message_id, reply_markup=telebot.types.InlineKeyboardMarkup().add(telebot.types.InlineKeyboardButton("🔙 返回", callback_data="back_admin")))
        bot.register_next_step_handler(call.message, admin_unban_handler)
    elif action == "auth":
        bot.edit_message_text("🔑 授权用户\n━━━━━━━━━━━━━━━━━━━━\n请输入要授权的用户ID：", call.message.chat.id, call.message.message_id, reply_markup=telebot.types.InlineKeyboardMarkup().add(telebot.types.InlineKeyboardButton("🔙 返回", callback_data="back_admin")))
        bot.register_next_step_handler(call.message, admin_auth_handler)
    elif action == "deauth":
        bot.edit_message_text("🔒 取消授权\n━━━━━━━━━━━━━━━━━━━━\n请输入要取消授权的用户ID：", call.message.chat.id, call.message.message_id, reply_markup=telebot.types.InlineKeyboardMarkup().add(telebot.types.InlineKeyboardButton("🔙 返回", callback_data="back_admin")))
        bot.register_next_step_handler(call.message, admin_deauth_handler)
    elif action == "switch":
        show_feature_switches(call, 0)
    bot.answer_callback_query(call.id)

USERS_PER_PAGE = 15

def show_user_list_page(call, page=0):
    all_users = DBUtils.get_all_users()
    if not all_users:
        bot.edit_message_text("暂无用户", call.message.chat.id, call.message.message_id, reply_markup=telebot.types.InlineKeyboardMarkup().add(telebot.types.InlineKeyboardButton("🔙 返回", callback_data="back_admin")))
        return
    total = len(all_users)
    start = page * USERS_PER_PAGE
    end = min(start + USERS_PER_PAGE, total)
    text = f"👤 用户列表（{total}人）\n━━━━━━━━━━━━━━━━━━━━\n"
    for i in range(start, end):
        uid, username, points, diamonds, auth, banned, invite_count = all_users[i]
        status = "❌" if banned else "✅"
        auth_icon = "🔑" if auth else ""
        text += f"{status} {uid} | {username} | {points}分 | {diamonds}💎 {auth_icon}\n"
    keyboard = telebot.types.InlineKeyboardMarkup(row_width=2)
    nav = []
    if page > 0:
        nav.append(telebot.types.InlineKeyboardButton("⬅️ 上一页", callback_data=f"admin_users_page_{page-1}"))
    if end < total:
        nav.append(telebot.types.InlineKeyboardButton("➡️ 下一页", callback_data=f"admin_users_page_{page+1}"))
    if nav:
        keyboard.add(*nav)
    keyboard.add(telebot.types.InlineKeyboardButton("🔙 返回", callback_data="back_admin"))
    bot.edit_message_text(text, call.message.chat.id, call.message.message_id, reply_markup=keyboard)

@bot.callback_query_handler(func=lambda call: call.data.startswith("admin_users_page_"))
def handle_admin_users_page(call):
    if call.from_user.id not in ADMIN_IDS:
        bot.answer_callback_query(call.id, "无权限操作！", show_alert=True)
        return
    page = int(call.data.replace("admin_users_page_", ""))
    show_user_list_page(call, page)
    bot.answer_callback_query(call.id)

SWITCH_PER_PAGE = 6

def get_all_feature_labels():
    return {'man': '慢线假地址', 'dy': '抖音反', 'zhend': '拼接真地址', 'dk': '大库户籍地', 'mxh': '名下号',
            'eys': '二要素核验', 'sys': '三要素核验', 'face': '人脸核验', 'yhk': '银行卡归属地',
            'k3': '银行卡三要素', 'k4': '银行卡四要素', 'id_extract': '身份证提取'}

def show_feature_switches(call, page=0):
    all_features = list(get_all_feature_labels().items())
    total = len(all_features)
    start = page * SWITCH_PER_PAGE
    end = min(start + SWITCH_PER_PAGE, total)
    text = f"🔀 功能开关（{page+1}/{(total+SWITCH_PER_PAGE-1)//SWITCH_PER_PAGE}页）\n━━━━━━━━━━━━━━━━━━━━\n"
    keyboard = telebot.types.InlineKeyboardMarkup(row_width=1)
    for i in range(start, end):
        fname, flabel = all_features[i]
        enabled = DBUtils.is_feature_enabled(fname)
        icon = "🟢" if enabled else "🔴"
        keyboard.add(telebot.types.InlineKeyboardButton(f"{icon} {flabel}", callback_data=f"switch_toggle_{fname}"))
    nav = []
    if page > 0:
        nav.append(telebot.types.InlineKeyboardButton("⬅️ 上一页", callback_data=f"switch_page_{page-1}"))
    if end < total:
        nav.append(telebot.types.InlineKeyboardButton("➡️ 下一页", callback_data=f"switch_page_{page+1}"))
    if nav:
        keyboard.row(*nav)
    keyboard.add(telebot.types.InlineKeyboardButton("🔙 返回主菜单", callback_data="back_admin"))
    bot.edit_message_text(text, call.message.chat.id, call.message.message_id, reply_markup=keyboard)

@bot.callback_query_handler(func=lambda call: call.data.startswith("switch_toggle_"))
def handle_switch_toggle(call):
    if call.from_user.id not in ADMIN_IDS:
        bot.answer_callback_query(call.id, "无权限操作！", show_alert=True)
        return
    feature = call.data.replace("switch_toggle_", "")
    current = DBUtils.is_feature_enabled(feature)
    DBUtils.set_feature_switch(feature, not current)
    label = get_all_feature_labels().get(feature, feature)
    bot.answer_callback_query(call.id, f"{'关闭' if current else '开启'} {label}", show_alert=True)
    show_feature_switches(call, 0)

@bot.callback_query_handler(func=lambda call: call.data.startswith("switch_page_"))
def handle_switch_page(call):
    if call.from_user.id not in ADMIN_IDS:
        bot.answer_callback_query(call.id, "无权限操作！", show_alert=True)
        return
    page = int(call.data.replace("switch_page_", ""))
    show_feature_switches(call, page)
    bot.answer_callback_query(call.id)

@bot.callback_query_handler(func=lambda call: call.data in ("price_default", "price_user", "price_view", "price_custom_list"))
def handle_price_callback(call):
    if call.from_user.id not in ADMIN_IDS:
        bot.answer_callback_query(call.id, "无权限操作！", show_alert=True)
        return
    action = call.data.replace("price_", "")
    if action == "default":
        bot.edit_message_text("📝 设置默认价格\n━━━━━━━━━━━━━━━━━━━━\n请选择要设置的服务：", call.message.chat.id, call.message.message_id, reply_markup=build_service_keyboard("price_set"))
    elif action == "user":
        bot.edit_message_text("👤 设置用户单独价格\n━━━━━━━━━━━━━━━━━━━━\n请选择服务后输入：用户ID 价格\n格式：用户ID 价格\n示例：123456 15", call.message.chat.id, call.message.message_id, reply_markup=build_service_keyboard("price_user"))
    elif action == "view":
        prices = DBUtils.get_all_service_prices()
        text = "📋 当前服务价格（默认）\n━━━━━━━━━━━━━━━━━━━━\n"
        for name, price in prices:
            label = "🐢 " + get_service_label(name)
            text += f"{label}：{price} 💎\n"
        bot.edit_message_text(text, call.message.chat.id, call.message.message_id, reply_markup=telebot.types.InlineKeyboardMarkup().add(telebot.types.InlineKeyboardButton("🔙 返回", callback_data="back_price")))
    elif action == "custom_list":
        show_custom_price_list(call, 0)
    bot.answer_callback_query(call.id)

@bot.callback_query_handler(func=lambda call: call.data.startswith("price_set_"))
def handle_price_set_callback(call):
    if call.from_user.id not in ADMIN_IDS:
        bot.answer_callback_query(call.id, "无权限操作！", show_alert=True)
        return
    service = call.data.replace("price_set_", "")
    label = get_service_label(service)
    bot.edit_message_text(f"📝 设置「{label}」默认价格\n━━━━━━━━━━━━━━━━━━━━\n当前价格：{DBUtils.get_service_price(service)} 💎\n请输入新价格（数字）：", call.message.chat.id, call.message.message_id, reply_markup=telebot.types.InlineKeyboardMarkup().add(telebot.types.InlineKeyboardButton("🔙 取消", callback_data="back_price")))
    bot.register_next_step_handler(call.message, admin_price_set_handler, service)

@bot.callback_query_handler(func=lambda call: call.data.startswith("price_user_"))
def handle_price_user_callback(call):
    if call.from_user.id not in ADMIN_IDS:
        bot.answer_callback_query(call.id, "无权限操作！", show_alert=True)
        return
    service = call.data.replace("price_user_", "")
    label = get_service_label(service)
    bot.edit_message_text(f"👤 设置「{label}」用户单独价格\n━━━━━━━━━━━━━━━━━━━━\n格式：用户ID 价格\n示例：123456 15\n\n输入后该用户使用此价格，不受默认价格影响", call.message.chat.id, call.message.message_id, reply_markup=telebot.types.InlineKeyboardMarkup().add(telebot.types.InlineKeyboardButton("🔙 取消", callback_data="back_price")))
    bot.register_next_step_handler(call.message, admin_price_user_handler, service)

CUSTOM_PRICE_PER_PAGE = 5

def show_custom_price_list(call, page=0):
    all_rows = DBUtils.get_all_user_service_prices()
    if not all_rows:
        bot.edit_message_text("📊 暂无设置单独价格的用户", call.message.chat.id, call.message.message_id, reply_markup=telebot.types.InlineKeyboardMarkup().add(telebot.types.InlineKeyboardButton("🔙 返回", callback_data="back_price")))
        return
    from collections import OrderedDict
    user_prices = OrderedDict()
    for uid, username, service_name, price in all_rows:
        if uid not in user_prices:
            user_prices[uid] = {'username': username, 'services': []}
        user_prices[uid]['services'].append((service_name, price))
    user_list = list(user_prices.items())
    total = len(user_list)
    start = page * CUSTOM_PRICE_PER_PAGE
    end = min(start + CUSTOM_PRICE_PER_PAGE, total)
    text = f"📊 单独价格用户（{total}人）\n━━━━━━━━━━━━━━━━━━━━\n"
    keyboard = telebot.types.InlineKeyboardMarkup(row_width=1)
    for i in range(start, end):
        uid, info = user_list[i]
        uname = info['username'] or '未知'
        svc_str = ' | '.join([f"{get_service_label(s)}:{p}💎" for s, p in info['services']])
        text += f"{i+1}. {uid} ({uname})\n   {svc_str}\n"
        keyboard.add(telebot.types.InlineKeyboardButton(f"✏️ {uid} - {uname}", callback_data=f"price_edit_user_{uid}"))
    nav = []
    if page > 0:
        nav.append(telebot.types.InlineKeyboardButton("⬅️ 上一页", callback_data=f"price_custom_page_{page-1}"))
    if end < total:
        nav.append(telebot.types.InlineKeyboardButton("➡️ 下一页", callback_data=f"price_custom_page_{page+1}"))
    if nav:
        keyboard.row(*nav)
    keyboard.add(telebot.types.InlineKeyboardButton("🔙 返回", callback_data="back_price"))
    bot.edit_message_text(text, call.message.chat.id, call.message.message_id, reply_markup=keyboard)

@bot.callback_query_handler(func=lambda call: call.data.startswith("price_custom_page_"))
def handle_price_custom_page(call):
    if call.from_user.id not in ADMIN_IDS:
        bot.answer_callback_query(call.id, "无权限操作！", show_alert=True)
        return
    page = int(call.data.replace("price_custom_page_", ""))
    show_custom_price_list(call, page)
    bot.answer_callback_query(call.id)

@bot.callback_query_handler(func=lambda call: call.data.startswith("price_edit_user_"))
def handle_price_edit_user(call):
    if call.from_user.id not in ADMIN_IDS:
        bot.answer_callback_query(call.id, "无权限操作！", show_alert=True)
        return
    uid = int(call.data.replace("price_edit_user_", ""))
    user = DBUtils.get_user(uid)
    username = user['username'] if user else '未知'
    user_prices = DBUtils.get_user_service_prices(uid)
    keyboard = telebot.types.InlineKeyboardMarkup(row_width=1)
    for svc, price in user_prices:
        label = get_service_label(svc)
        keyboard.add(telebot.types.InlineKeyboardButton(f"✏️ {label}：当前 {price}💎", callback_data=f"price_modify_{uid}_{svc}_{price}"))
    keyboard.add(telebot.types.InlineKeyboardButton("🔙 返回列表", callback_data="price_custom_list"))
    bot.edit_message_text(f"✏️ 修改 {uid} ({username}) 的价格\n━━━━━━━━━━━━━━━━━━━━", call.message.chat.id, call.message.message_id, reply_markup=keyboard)
    bot.answer_callback_query(call.id)

@bot.callback_query_handler(func=lambda call: call.data.startswith("price_modify_"))
def handle_price_modify(call):
    if call.from_user.id not in ADMIN_IDS:
        bot.answer_callback_query(call.id, "无权限操作！", show_alert=True)
        return
    parts = call.data.replace("price_modify_", "").split("_")
    uid = int(parts[0])
    svc = parts[1]
    old_price = int(parts[2])
    label = get_service_label(svc)
    bot.edit_message_text(f"✏️ 修改 {uid} 的 {label} 价格\n━━━━━━━━━━━━━━━━━━━━\n当前价格：{old_price}💎\n\n请输入新价格：",
        call.message.chat.id, call.message.message_id, reply_markup=telebot.types.InlineKeyboardMarkup().add(telebot.types.InlineKeyboardButton("🔙 取消", callback_data=f"price_edit_user_{uid}")))
    bot.register_next_step_handler(call.message, admin_price_modify_handler, uid, svc)

def admin_price_modify_handler(message, uid, svc):
    try:
        new_price = int(message.text.strip())
        if new_price < 0:
            bot.reply_to(message, "价格不能为负数！")
            return
    except (ValueError, AttributeError):
        bot.reply_to(message, "格式错误！请输入数字")
        return
    DBUtils.set_user_service_price(uid, svc, new_price)
    label = get_service_label(svc)
    bot.reply_to(message, f"✅ 已将用户 {uid} 的 {label} 价格修改为 {new_price}💎")

@bot.callback_query_handler(func=lambda call: call.data == "back_price")
def back_price_callback(call):
    if call.from_user.id not in ADMIN_IDS:
        bot.answer_callback_query(call.id, "无权限操作！", show_alert=True)
        return
    bot.edit_message_text("⚙️ 价格管理\n━━━━━━━━━━━━━━━━━━━━", call.message.chat.id, call.message.message_id, reply_markup=build_price_keyboard())
    bot.answer_callback_query(call.id)

@bot.callback_query_handler(func=lambda call: call.data == "back_admin")
def back_admin_callback(call):
    if call.from_user.id not in ADMIN_IDS:
        bot.answer_callback_query(call.id, "无权限操作！", show_alert=True)
        return
    pending_count = DBUtils.get_pending_order_count()
    all_users = DBUtils.get_all_users()
    total_users = len(all_users)
    total_points = sum(u[2] for u in all_users)
    total_diamonds = sum(u[3] for u in all_users)
    admin_text = f"""
👑 管理员面板
━━━━━━━━━━━━━━━━━━━━
📊 系统统计
• 用户总数：{total_users}
• 待处理订单：{pending_count}
• 总积分：{total_points}
• 总钻石：{total_diamonds}
━━━━━━━━━━━━━━━━━━━━
请选择操作：
    """
    bot.edit_message_text(admin_text, call.message.chat.id, call.message.message_id, reply_markup=build_admin_keyboard())
    bot.answer_callback_query(call.id)

@bot.callback_query_handler(func=lambda call: call.data.startswith("order_"))
def handle_order_callback(call):
    if call.from_user.id not in ADMIN_IDS:
        bot.answer_callback_query(call.id, "无权限操作！", show_alert=True)
        return
    data = call.data.replace("order_", "")
    if data == "refresh":
        orders_list = DBUtils.get_pending_orders()
        if not orders_list:
            bot.edit_message_text("📋 暂无待处理订单", call.message.chat.id, call.message.message_id, reply_markup=telebot.types.InlineKeyboardMarkup().add(telebot.types.InlineKeyboardButton("🔙 返回", callback_data="back_admin")))
            return
        bot.edit_message_text("📋 待处理订单\n━━━━━━━━━━━━━━━━━━━━", call.message.chat.id, call.message.message_id, reply_markup=build_order_list_keyboard(orders_list, 0))
    elif data == "list":
        orders_list = DBUtils.get_pending_orders()
        if not orders_list:
            bot.edit_message_text("📋 暂无待处理订单", call.message.chat.id, call.message.message_id, reply_markup=telebot.types.InlineKeyboardMarkup().add(telebot.types.InlineKeyboardButton("🔙 返回", callback_data="back_admin")))
            return
        bot.edit_message_text("📋 待处理订单\n━━━━━━━━━━━━━━━━━━━━", call.message.chat.id, call.message.message_id, reply_markup=build_order_list_keyboard(orders_list, 0))
    elif data.startswith("page_"):
        page = int(data.replace("page_", ""))
        orders_list = DBUtils.get_pending_orders()
        bot.edit_message_text("📋 待处理订单\n━━━━━━━━━━━━━━━━━━━━", call.message.chat.id, call.message.message_id, reply_markup=build_order_list_keyboard(orders_list, page))
    elif data.startswith("detail_"):
        order_no = data.replace("detail_", "")
        order = DBUtils.get_order_by_no(order_no)
        if not order:
            bot.answer_callback_query(call.id, "订单不存在！", show_alert=True)
            return
        service_label = get_service_label(order['service_name'])
        service_data = order['service_data']
        content = ""
        if order['service_name'] == 'dy':
            content = f"抖音号：{service_data.get('dy_id', '')}"
        else:
            content = f"姓名：{service_data.get('name', '')}\n身份证：{service_data.get('id_card', '')}"
        user = DBUtils.get_user(order['user_id'])
        username = user['username'] if user else "未知"
        text = f"📄 订单详情\n━━━━━━━━━━━━━━━━━━━━\n订单号：{order_no}\n用户ID：{order['user_id']}\n用户昵称：{username}\n服务：{service_label}\n提交内容：\n{content}\n消耗：{order['price']} 💎\n状态：⏳ 待处理\n提交时间：{order['created_at']}\n━━━━━━━━━━━━━━━━━━━━"
        bot.edit_message_text(text, call.message.chat.id, call.message.message_id, reply_markup=build_order_action_keyboard(order_no))
    elif data.startswith("process_"):
        order_no = data.replace("process_", "")
        order = DBUtils.get_order_by_no(order_no)
        if not order or order['status'] != 'pending':
            bot.answer_callback_query(call.id, "订单已处理或不存在！", show_alert=True)
            return
        user = DBUtils.get_user(order['user_id'])
        username = user['username'] if user else "未知"
        service_label = get_service_label(order['service_name'])
        service_data = order['service_data']
        content = ""
        if order['service_name'] == 'dy':
            content = f"抖音号：{service_data.get('dy_id', '')}"
        else:
            content = f"姓名：{service_data.get('name', '')}\n身份证：{service_data.get('id_card', '')}"
        text = f"✅ 处理订单：{order_no}\n━━━━━━━━━━━━━━━━━━━━\n用户ID：{order['user_id']}\n用户昵称：{username}\n服务：{service_label}\n内容：\n{content}\n消耗：{order['price']} 💎\n━━━━━━━━━━━━━━━━━━━━\n请回复此消息发送回单内容：\n• 发送文字\n• 发送图片\n• 发送文件"
        bot.edit_message_text(text, call.message.chat.id, call.message.message_id, reply_markup=telebot.types.InlineKeyboardMarkup().add(telebot.types.InlineKeyboardButton("🔙 取消", callback_data=f"order_detail_{order_no}")))
        bot.answer_callback_query(call.id, "请回复此消息发送回单", show_alert=True)
    elif data.startswith("cancel_confirm_"):
        order_no = data.replace("cancel_confirm_", "")
        order = DBUtils.get_order_by_no(order_no)
        if not order or order['status'] != 'pending':
            bot.answer_callback_query(call.id, "订单已处理或不存在！", show_alert=True)
            return
        DBUtils.cancel_order(order_no)
        DBUtils.update_user_diamonds(order['user_id'], order['price'])
        DBUtils.log_diamond_transaction(order['user_id'], 'refund', order['price'], f'订单退回 {order_no}', order_no)
        bot.send_message(order['user_id'],
            f"📨 您的订单已被取消\n━━━━━━━━━━━━━━━━━━━━\n订单号：{order_no}\n服务：{get_service_label(order['service_name'])}\n原因：查询为空\n💎 已退回 {order['price']} 钻石")
        bot.edit_message_text(f"✅ 已退回 {order['price']} 💎 给用户 {order['user_id']}\n订单：{order_no} 已取消", call.message.chat.id, call.message.message_id, reply_markup=telebot.types.InlineKeyboardMarkup().add(telebot.types.InlineKeyboardButton("📋 返回订单列表", callback_data="order_list")))
    elif data.startswith("cancel_"):
        order_no = data.replace("cancel_", "")
        order = DBUtils.get_order_by_no(order_no)
        if not order or order['status'] != 'pending':
            bot.answer_callback_query(call.id, "订单已处理或不存在！", show_alert=True)
            return
        if order['service_name'] == 'zhend':
            text = f"❌ 查询为空：{order_no}\n━━━━━━━━━━━━━━━━━━━━\n请选择退费方式："
            keyboard = telebot.types.InlineKeyboardMarkup(row_width=1)
            keyboard.add(
                telebot.types.InlineKeyboardButton(f"📷 照片+户籍地全空 → 退还全部 {order['price']}💎", callback_data=f"zhend_refund_all_{order_no}"),
                telebot.types.InlineKeyboardButton(f"📷 照片为空 → 退还20💎 + 发送回单", callback_data=f"zhend_refund_photo_{order_no}"),
                telebot.types.InlineKeyboardButton(f"📋 户籍地为空 → 退还10💎 + 发送回单", callback_data=f"zhend_refund_addr_{order_no}"),
                telebot.types.InlineKeyboardButton("🔙 返回订单详情", callback_data=f"order_detail_{order_no}")
            )
            bot.edit_message_text(text, call.message.chat.id, call.message.message_id, reply_markup=keyboard)
        else:
            text = f"❌ 查询为空：{order_no}\n━━━━━━━━━━━━━━━━━━━━\n确认退回 {order['price']} 💎 给用户？"
            bot.edit_message_text(text, call.message.chat.id, call.message.message_id, reply_markup=build_order_cancel_confirm_keyboard(order_no))
    bot.answer_callback_query(call.id)

# ==================== 拼接真地址部分退费回调 ====================
@bot.callback_query_handler(func=lambda call: call.data.startswith("zhend_refund_all_"))
def handle_zhend_refund_all(call):
    if call.from_user.id not in ADMIN_IDS:
        bot.answer_callback_query(call.id, "无权限操作！", show_alert=True)
        return
    order_no = call.data.replace("zhend_refund_all_", "")
    order = DBUtils.get_order_by_no(order_no)
    if not order or order['status'] != 'pending':
        bot.answer_callback_query(call.id, "订单已处理或不存在！", show_alert=True)
        return
    DBUtils.cancel_order(order_no)
    DBUtils.update_user_diamonds(order['user_id'], order['price'])
    DBUtils.log_diamond_transaction(order['user_id'], 'refund', order['price'], f'拼接真地址全退 {order_no}', order_no)
    bot.send_message(order['user_id'],
        f"📨 您的订单已被取消\n━━━━━━━━━━━━━━━━━━━━\n订单号：{order_no}\n服务：拼接真地址\n原因：查询为空（照片+户籍地全空）\n💎 已退回 {order['price']} 钻石")
    bot.edit_message_text(f"✅ 照片+户籍地全空\n已退回 {order['price']} 💎 给用户 {order['user_id']}\n订单：{order_no} 已取消", call.message.chat.id, call.message.message_id, reply_markup=telebot.types.InlineKeyboardMarkup().add(telebot.types.InlineKeyboardButton("📋 返回订单列表", callback_data="order_list")))
    bot.answer_callback_query(call.id)

@bot.callback_query_handler(func=lambda call: call.data.startswith("zhend_refund_photo_"))
def handle_zhend_refund_photo(call):
    if call.from_user.id not in ADMIN_IDS:
        bot.answer_callback_query(call.id, "无权限操作！", show_alert=True)
        return
    order_no = call.data.replace("zhend_refund_photo_", "")
    order = DBUtils.get_order_by_no(order_no)
    if not order or order['status'] != 'pending':
        bot.answer_callback_query(call.id, "订单已处理或不存在！", show_alert=True)
        return
    DBUtils.cancel_order(order_no)
    refund_amount = 20
    DBUtils.update_user_diamonds(order['user_id'], refund_amount)
    DBUtils.log_diamond_transaction(order['user_id'], 'refund', refund_amount, f'拼接真地址照片为空退20 {order_no}', order_no)
    text = f"📷 照片为空退费：{order_no}\n━━━━━━━━━━━━━━━━━━━━\n退费：{order_no}\n用户ID：{order['user_id']}\n已退回 20💎 给用户\n\n请回复此消息发送回单内容（户籍地）：\n• 发送文字\n• 发送图片\n• 发送文件"
    bot.edit_message_text(text, call.message.chat.id, call.message.message_id, reply_markup=telebot.types.InlineKeyboardMarkup().add(telebot.types.InlineKeyboardButton("🔙 返回订单列表", callback_data="order_list")))
    bot.answer_callback_query(call.id, "请回复此消息发送户籍地回单", show_alert=True)

@bot.callback_query_handler(func=lambda call: call.data.startswith("zhend_refund_addr_"))
def handle_zhend_refund_addr(call):
    if call.from_user.id not in ADMIN_IDS:
        bot.answer_callback_query(call.id, "无权限操作！", show_alert=True)
        return
    order_no = call.data.replace("zhend_refund_addr_", "")
    order = DBUtils.get_order_by_no(order_no)
    if not order or order['status'] != 'pending':
        bot.answer_callback_query(call.id, "订单已处理或不存在！", show_alert=True)
        return
    DBUtils.cancel_order(order_no)
    refund_amount = 10
    DBUtils.update_user_diamonds(order['user_id'], refund_amount)
    DBUtils.log_diamond_transaction(order['user_id'], 'refund', refund_amount, f'拼接真地址户籍地为空退10 {order_no}', order_no)
    text = f"📋 户籍地为空退费：{order_no}\n━━━━━━━━━━━━━━━━━━━━\n退费：{order_no}\n用户ID：{order['user_id']}\n已退回 10💎 给用户\n\n请回复此消息发送回单内容（照片）：\n• 发送文字\n• 发送图片\n• 发送文件"
    bot.edit_message_text(text, call.message.chat.id, call.message.message_id, reply_markup=telebot.types.InlineKeyboardMarkup().add(telebot.types.InlineKeyboardButton("🔙 返回订单列表", callback_data="order_list")))
    bot.answer_callback_query(call.id, "请回复此消息发送照片回单", show_alert=True)

def admin_points_handler(message):
    user_id = message.from_user.id
    if user_id not in ADMIN_IDS:
        return
    try:
        parts = message.text.strip().split()
        if len(parts) != 2:
            bot.reply_to(message, "格式错误！请输入：用户ID 积分数量")
            return
        target_id = int(parts[0])
        points = int(parts[1])
        if points == 0:
            bot.reply_to(message, "请输入非零数字！")
            return
        DBUtils.update_user_points(target_id, points)
        user = DBUtils.get_user(target_id)
        bot.reply_to(message, f"✅ 操作成功！\n用户 {target_id} 积分变化：{points}\n当前积分：{user['points'] if user else '未知'}")
    except:
        bot.reply_to(message, "格式错误！请输入：用户ID 积分数量")

def admin_diamonds_handler(message):
    user_id = message.from_user.id
    if user_id not in ADMIN_IDS:
        return
    try:
        parts = message.text.strip().split()
        if len(parts) != 2:
            bot.reply_to(message, "格式错误！请输入：用户ID 钻石数量")
            return
        target_id = int(parts[0])
        diamonds = int(parts[1])
        if diamonds == 0:
            bot.reply_to(message, "请输入非零数字！")
            return
        DBUtils.update_user_diamonds(target_id, diamonds)
        DBUtils.log_diamond_transaction(target_id, 'admin_add' if diamonds > 0 else 'admin_sub', diamonds, f'管理员操作')
        user = DBUtils.get_user(target_id)
        bot.reply_to(message, f"✅ 操作成功！\n用户 {target_id} 钻石变化：{diamonds}\n当前钻石：{user['diamonds'] if user else '未知'}")
    except:
        bot.reply_to(message, "格式错误！请输入：用户ID 钻石数量")

def admin_price_set_handler(message, service):
    user_id = message.from_user.id
    if user_id not in ADMIN_IDS:
        return
    try:
        price = int(message.text.strip())
        if price < 0:
            bot.reply_to(message, "价格不能为负数！")
            return
        old_price = DBUtils.get_service_price(service)
        DBUtils.set_service_price(service, price)
        label = get_service_label(service)
        bot.reply_to(message, f"✅ 已更新「{label}」默认价格\n{old_price} 💎 → {price} 💎\n（已重置该服务所有用户单独价格）")
    except:
        bot.reply_to(message, "请输入有效的数字！")

def admin_price_user_handler(message, service):
    user_id = message.from_user.id
    if user_id not in ADMIN_IDS:
        return
    try:
        parts = message.text.strip().split()
        if len(parts) != 2:
            bot.reply_to(message, "格式错误！请输入：用户ID 价格")
            return
        target_id = int(parts[0])
        price = int(parts[1])
        if price < 0:
            bot.reply_to(message, "价格不能为负数！")
            return
        DBUtils.set_user_service_price(target_id, service, price)
        label = get_service_label(service)
        bot.reply_to(message, f"✅ 用户 {target_id} 的「{label}」已设单独价格：{price} 💎\n（优先级高于全局默认）")
    except:
        bot.reply_to(message, "格式错误！请输入：用户ID 价格")

def admin_ban_handler(message):
    user_id = message.from_user.id
    if user_id not in ADMIN_IDS:
        return
    try:
        target_id = int(message.text.strip())
        DBUtils.update_ban_status(target_id, 1)
        bot.reply_to(message, f"✅ 用户 {target_id} 已封禁")
    except:
        bot.reply_to(message, "请输入有效的用户ID！")

def admin_unban_handler(message):
    user_id = message.from_user.id
    if user_id not in ADMIN_IDS:
        return
    try:
        target_id = int(message.text.strip())
        DBUtils.update_ban_status(target_id, 0)
        bot.reply_to(message, f"✅ 用户 {target_id} 已解封")
    except:
        bot.reply_to(message, "请输入有效的用户ID！")

def admin_auth_handler(message):
    user_id = message.from_user.id
    if user_id not in ADMIN_IDS:
        return
    try:
        target_id = int(message.text.strip())
        DBUtils.update_authorization(target_id, 1)
        bot.reply_to(message, f"✅ 用户 {target_id} 已授权（免积分使用）")
    except:
        bot.reply_to(message, "请输入有效的用户ID！")

def admin_deauth_handler(message):
    user_id = message.from_user.id
    if user_id not in ADMIN_IDS:
        return
    try:
        target_id = int(message.text.strip())
        DBUtils.update_authorization(target_id, 0)
        bot.reply_to(message, f"✅ 用户 {target_id} 已取消授权")
    except:
        bot.reply_to(message, "请输入有效的用户ID！")

def admin_broadcast_handler(message):
    user_id = message.from_user.id
    if user_id not in ADMIN_IDS:
        return
    all_users = DBUtils.get_all_users()
    success_count = 0
    fail_count = 0
    msg = bot.reply_to(message, f"正在广播给 {len(all_users)} 名用户...")
    for uid, _, _, _, _, banned, _ in all_users:
        if banned:
            continue
        try:
            if message.text:
                bot.send_message(uid, f"📢 管理员广播：\n\n{message.text}")
            elif message.photo:
                bot.send_photo(uid, message.photo[-1].file_id, caption="📢 管理员广播：")
            elif message.document:
                bot.send_document(uid, message.document.file_id, caption="📢 管理员广播：")
            else:
                continue
            success_count += 1
            time.sleep(0.05)
        except:
            fail_count += 1
    bot.edit_message_text(f"📢 广播完成！\n成功：{success_count} 人\n失败：{fail_count} 人", user_id, msg.message_id)

if __name__ == '__main__':
    logger.info("机器人启动中...")
    logger.info(f"必加频道: {CHANNEL_LINK}")
    logger.info(f"管理员列表: {ADMIN_IDS}")
    try:
        bot.infinity_polling(none_stop=True, timeout=60)
    except Exception as e:
        logger.error(f"机器人异常：{e}")