import asyncio
import re
from datetime import datetime
import pymysql
from telegram import Update
from telegram.ext import Application, CommandHandler, MessageHandler, filters, ContextTypes

TOKEN = '8110161043:AAHUpHA9x2KXCvGhJfDESZncFB2_8EAZR_A'
BOT_USERNAME = 'lobster123_bot'
CONTROLLER = "Teolllong"

minBanker = 1000
bankerDetectTime = 10
betDetectTime = 10
max_attempts = 3
bet_min_ratio = 0.01
bet_max_ratio = 0.1

# 全局状态
listening = False
betting = False
awaiting_result = False
final_result = None
highest_bid = 0
highest_user = ""
attempt = 0
force_stop = False
bet_min = 0
bet_max = 0
bets = {}  # username -> list of {'type': str, 'amount': int}

group_chat_id = None


valid_types = ['单数', '双数', '大', '小']

# 📌 从数据库加载配置
def update_config_from_db():
    global TOKEN, BOT_USERNAME, CONTROLLER
    global minBanker, bankerDetectTime, betDetectTime, max_attempts, bet_min_ratio, bet_max_ratio

    try:
        connection = pymysql.connect(
            host='localhost',
            user='root',
            password='31031992',  # <<< 请改成真实密码
            database='lobster_bet',
            cursorclass=pymysql.cursors.DictCursor
        )
        with connection:
            with connection.cursor() as cursor:
                cursor.execute("SELECT key_name, value FROM bot_config")
                rows = cursor.fetchall()
                config = {row['key_name']: row['value'] for row in rows}

                TOKEN = config.get('TOKEN', TOKEN)
                BOT_USERNAME = config.get('BOT_USERNAME', BOT_USERNAME)
                CONTROLLER = config.get('CONTROLLER', CONTROLLER)

                minBanker = int(config.get('minBanker', minBanker))
                bankerDetectTime = int(config.get('bankerDetectTime', bankerDetectTime))
                betDetectTime = int(config.get('betDetectTime', betDetectTime))
                max_attempts = int(config.get('max_attempts', max_attempts))
                bet_min_ratio = float(config.get('bet_min_ratio', bet_min_ratio))
                bet_max_ratio = float(config.get('bet_max_ratio', bet_max_ratio))

                print("[配置已更新]")
    except Exception as e:
        print(f"[配置更新异常]: {e}")

async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
    global listening, betting, awaiting_result, final_result, highest_bid, highest_user
    global attempt, force_stop, bet_min, bet_max, bets

    username = update.message.from_user.username
    text = update.message.text.strip()
    chat_id = update.message.chat.id

    print(f'[{datetime.now()}] {username}: {text}')

    # 管理员指令
    if username == CONTROLLER:
        print(f'[{datetime.now()}] {username}: {text}')
        if text == "开始" and not listening and not betting:
            update_config_from_db()  # 📌 管理员说“开始”时加载配置
            listening = True
            force_stop = False
            highest_bid = 0
            highest_user = ""
            attempt = 1
            if update.message.chat.type in ['group', 'supergroup']:
                group_chat_id = chat_id  # ✅ 只记录群聊 ID
                print(group_chat_id)
            await update.message.reply_text(
                f"开始标桩！最低标桩为 {minBanker} 分，限时 {bankerDetectTime} 秒。（第 {attempt} 次）")
            asyncio.create_task(start_listening(chat_id, context))
            return
        elif text == "结束" and (listening or betting or awaiting_result):
            force_stop = True
            listening = betting = awaiting_result = False
            await update.message.reply_text("游戏已被管理员强制结束！")
            return

    # 标桩阶段
    if listening and username != BOT_USERNAME:
        try:
            number = int(text)
            if number >= minBanker:
                if highest_bid == 0 or number >= highest_bid + 100:
                    highest_bid = number
                    highest_user = username
                    await update.message.reply_text(f"{username} 出价：{number}")
        except ValueError:
            pass

    # 下注阶段
    elif betting and username != highest_user and username != BOT_USERNAME:
        parts = text.split()
        if len(parts) != 2:
            await update.message.reply_text("格式错误，应为：种类 金额（如 单数 300）")
            return
        bet_type_raw, amount_str = parts
        bet_type = None
        if bet_type_raw in valid_types:
            bet_type = bet_type_raw
        else:
            match = re.match(r'^数字(\d+)$', bet_type_raw)
            if match:
                bet_type = f"数字{match.group(1)}"
        if not bet_type:
            await update.message.reply_text("下注种类无效，可用：单数、双数、大、小、数字X")
            return
        try:
            amount = int(amount_str)
            if not (bet_min <= amount <= bet_max):
                await update.message.reply_text(f"金额需在 {bet_min} ~ {bet_max} 之间")
                return
        except ValueError:
            await update.message.reply_text("金额必须是数字")
            return
        # 记录下注：同用户同种类取更高
        user_bets = bets.get(username, [])
        updated = False
        for b in user_bets:
            if b['type'] == bet_type:
                if amount > b['amount']:
                    b['amount'] = amount
                updated = True
                break
        if not updated:
            user_bets.append({'type': bet_type, 'amount': amount})
        bets[username] = user_bets
        await update.message.reply_text(f"{username} 成功下注：{bet_type} {amount}")

    # 开奖阶段
    elif awaiting_result and username == CONTROLLER:
        try:
            number = int(text)
            if 1 <= number <= 10:
                awaiting_result = False
                final_result = number
                await update.message.reply_text(f"收到开奖结果：{number}，正在统计...")
                await process_result(number, context, chat_id)
            else:
                await update.message.reply_text("请输入 1~10 的数字作为开奖结果")
        except ValueError:
            await update.message.reply_text("请输入 1~10 的数字作为开奖结果")

async def start_listening(chat_id, context):
    global listening, highest_bid, highest_user, attempt, force_stop, bet_min, bet_max, betting, bets
    emojis = ['⚡️', '⏳', '🔥', '🐇', '🚀']
    try:
        await asyncio.sleep(bankerDetectTime - 5)
        file_id = 'CAACAgEAAyEFAASoMy7IAAIBjGhmKY2pJcLgcpVQCJOFMyyz0tJnAAJJBAAChO1ZRQZkvDRwD8xfNgQ'
        await context.bot.send_sticker(chat_id=chat_id, sticker=file_id)
        await asyncio.sleep(5)
    except asyncio.CancelledError:
        return

    if force_stop: return
    listening = False
    if highest_bid > 0:
        await context.bot.send_message(chat_id, text=f"时间到！最高标桩：{highest_bid} 分，由 @{highest_user} 出价。")
        bet_min = max(1, int(highest_bid * bet_min_ratio))
        bet_max = max(1, int(highest_bid * bet_max_ratio))
        betting = True
        bets = {}
        await context.bot.send_message(
            chat_id,
            text=f"进入下注环节（限时 {betDetectTime} 秒）：@{highest_user} 无需下注\n可下注：单数、双数、大、小、数字X\n金额范围：{bet_min} ~ {bet_max}")
        asyncio.create_task(start_betting(chat_id, context))
    else:
        if attempt < max_attempts:
            attempt += 1
            listening = True
            highest_bid = 0
            highest_user = ""
            await context.bot.send_message(chat_id, text=f"无人出价，自动重新开始（第 {attempt} 次）")
            asyncio.create_task(start_listening(chat_id, context))
        else:
            await context.bot.send_message(chat_id, text="无人出价，达到最大重试次数，游戏结束")

async def start_betting(chat_id, context):
    global betting, force_stop, awaiting_result, attempt, listening, highest_bid, highest_user
    emojis = ['⚡️', '⏳', '🔥', '🐇', '🚀']
    start_time = datetime.now()
    try:
        await asyncio.sleep(bankerDetectTime - 5)
        file_id = 'CAACAgEAAyEFAASoMy7IAAIBjGhmKY2pJcLgcpVQCJOFMyyz0tJnAAJJBAAChO1ZRQZkvDRwD8xfNgQ'
        await context.bot.send_sticker(chat_id=chat_id, sticker=file_id)
        await asyncio.sleep(5)
    except asyncio.CancelledError:
        return

    if force_stop: return
    betting = False
    if bets:
        summary = build_summary(start_time, datetime.now())
        awaiting_result = True
        await context.bot.send_message(chat_id, text=summary)
        await context.bot.send_message(chat_id, text="下注结束！请等待开奖结果，管理员请私聊我一个数字（1~10）")
    else:
        await context.bot.send_message(chat_id, text="无人下注。")
        if attempt < max_attempts:
            attempt += 1
            await context.bot.send_message(chat_id, text=f"重新开始标桩（第 {attempt} 次）")
            global listening, highest_bid, highest_user
            listening = True
            highest_bid = 0
            highest_user = ""
            asyncio.create_task(start_listening(chat_id, context))
        else:
            await context.bot.send_message(chat_id, text="无人下注且已达到最大重试次数，游戏结束。")

def build_summary(start_time, end_time):
    global highest_user, highest_bid, bets
    type_counts = {'单数': set(), '双数': set(), '大': set(), '小': set(), '数字': set()}
    total_amount = 0
    user_count = len(bets)
    detail_lines = []
    for user, user_bets in bets.items():
        for b in user_bets:
            total_amount += b['amount']
            t = b['type']
            if t in type_counts:
                type_counts[t].add(user)
            elif t.startswith('数字'):
                type_counts['数字'].add(user)
            detail_lines.append(f"{user:<10} {t:<10} {b['amount']}")
    return (
        "-----------------------------\n"
        f"标桩结束：{start_time.strftime('%H:%M:%S')}\n下注结束：{end_time.strftime('%H:%M:%S')}\n"
        "-----------------------------\n"
        f"庄家：@{highest_user}\n金额：{highest_bid}\n"
        "-----------------------------\n"
        f"玩家人数：{user_count} 总金额：{total_amount}\n"
        f"单数下注：{len(type_counts['单数'])}\n"
        f"双数下注：{len(type_counts['双数'])}\n"
        f"大下注：{len(type_counts['大'])}\n"
        f"小下注：{len(type_counts['小'])}\n"
        f"数字下注：{len(type_counts['数字'])}\n"
        "-----------------------------\n"
        f"{'玩家':<10} {'下注':<10} 金额\n" + "\n".join(detail_lines)
    )

# 新增一个处理贴图的回调
async def handle_sticker(update, context):
    sticker = update.message.sticker
    if sticker:
        file_id = sticker.file_id
        print(f"收到贴图 file_id: {file_id}")
        # 你也可以回复用户
        await update.message.reply_text(f"贴图的 file_id 是：{file_id}")

async def process_result(number, context, chat_id):
    global bets, highest_user, highest_bid, group_chat_id
    result_type = {
        '单双': '单数' if number % 2 == 1 else '双数',
        '大小': '小' if number <= 4 else '大',
        '数字': f"数字{number}"
    }

    now_str = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

    # 所有下注总额
    total_bets = sum(b['amount'] for user_bets in bets.values() for b in user_bets)

    # 找到所有中奖用户
    winning_users = set()
    for user, user_bets in bets.items():
        for b in user_bets:
            if (b['type'] == result_type['单双'] or b['type'] == result_type['大小']) or b['type'] == result_type['数字']:
                winning_users.add(user)
                break

    # 输的玩家下注金额总和
    lose_bets = 0
    for user, user_bets in bets.items():
        if user not in winning_users:
            lose_bets += sum(b['amount'] for b in user_bets)

    total_win = lose_bets

    # 计算实际赔付
    win_list = []
    for user, user_bets in bets.items():
        for b in user_bets:
            payout = 0
            if b['type'] == result_type['单双'] or b['type'] == result_type['大小']:
                payout = int(b['amount'] * 1.9)
            elif b['type'] == result_type['数字']:
                payout = int(b['amount'] * 7)
            if payout > 0:
                win_list.append({'user': user, 'type': b['type'], 'bet': b['amount'], 'payout': payout})

    win_list.sort(key=lambda x: x['payout'], reverse=True)

    remain = highest_bid
    actual_payouts = []

    for win in win_list:
        if remain >= win['payout']:
            actual = win['payout']
        else:
            actual = remain
        if actual > 0:
            actual_payouts.append({
                'user': win['user'],
                'type': win['type'],
                'bet': win['bet'],
                'should_payout': win['payout'],
                'actual_payout': actual
            })
            remain -= actual
        if remain <= 0:
            break

    total_paid = sum(a['actual_payout'] for a in actual_payouts)
    banker_after = highest_bid + total_win - total_paid

    if actual_payouts:
        lines = []
        for a in actual_payouts:
            lines.append(
                f"@{a['user']} {a['type']} 中！下注：{a['bet']} 应得：{a['should_payout']} 实际赔付：{a['actual_payout']}")
        detail = "\n".join(lines)
    else:
        detail = "无人中奖"

    msg = (
        "-----------------------------\n"
        f"🏆 开奖结果：{number}（{result_type['大小']}/{result_type['单双']}）\n"
        "-----------------------------\n"
        f"开奖时间：{now_str}\n"
        f"庄家：@{highest_user}\n标桩金额：{highest_bid}\n"
        f"赔付：{total_paid}                赢得：{total_win}\n"
        f"最后金额：{banker_after}\n"
        "-----------------------------\n"
        f"{detail}\n"
        "-----------------------------\n"
        f"总实际赔付：{total_paid}"
    )

    await context.bot.send_message(chat_id, text=msg)
    if group_chat_id:
        await context.bot.send_message(group_chat_id, text=msg)


async def start_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
    await update.message.reply_text('发送「开始」开始标桩，「结束」停止游戏。\n下注格式：种类 金额（如 单数 300）')

async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
    await update.message.reply_text('可下注：单数、双数、大、小、数字X\n例如：数字7 500')

async def error(update: Update, context: ContextTypes.DEFAULT_TYPE):
    print(f'Update {update} caused error {context.error}')

if __name__ == '__main__':
    print("Bot 正在运行中...")
    update_config_from_db()  # 第一次启动时也加载一次
    app = Application.builder().token(TOKEN).build()
    app.add_handler(CommandHandler('start', start_command))
    app.add_handler(CommandHandler('help', help_command))
    app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))
    # 处理贴图消息
    #app.add_handler(MessageHandler(filters.Sticker.ALL, handle_sticker))
    app.add_error_handler(error)
    app.run_polling(poll_interval=3)
