"""气氛组 + 小游戏 handler"""
import asyncio
import logging

import config
from services.message_utils import record_bot_message

from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
from telegram.ext import ApplicationHandlerStop, CallbackQueryHandler, ContextTypes, CommandHandler, MessageHandler, filters

from db.models import Action
from services.game_service import (
    get_trivia_question, check_trivia_answer,
    get_leaderboard, daily_checkin, get_scores_summary,
    SHOP_ITEMS, buy_shop_item, list_shop_items,
    parse_lottery_spec, create_lottery_event, lottery_condition_text, lottery_end_text,
    count_lottery_participants, join_lottery_event, draw_lottery_event,
)

logger = logging.getLogger("spam_guard")
PANEL_IDLE_SECONDS = 60

# 关键词触发
def panel_keyboard():
    return InlineKeyboardMarkup([
        [InlineKeyboardButton("👤 我的信息", callback_data="panel:me"), InlineKeyboardButton("✅ 签到", callback_data="panel:checkin")],
        [InlineKeyboardButton("🎁 发起抽奖", callback_data="panel:lottery"), InlineKeyboardButton("🛒 商城", callback_data="panel:shop")],
        [InlineKeyboardButton("📖 帮助", callback_data="panel:help")],
    ])


def schedule_panel_idle_delete(context: ContextTypes.DEFAULT_TYPE, message, seconds: int = PANEL_IDLE_SECONDS):
    tasks = context.bot_data.setdefault("panel_idle_tasks", {})
    key = (message.chat_id, message.message_id)
    old_task = tasks.pop(key, None)
    if old_task and not old_task.done():
        old_task.cancel()

    async def _delete_later():
        try:
            await asyncio.sleep(seconds)
            await message.delete()
        except asyncio.CancelledError:
            return
        except Exception:
            pass
        finally:
            tasks.pop(key, None)

    tasks[key] = asyncio.create_task(_delete_later())


TRIGGER_REACTIONS = {
    "谢谢": "👍❤️",
    "感谢": "👍❤️🎉",
    "哈哈": "😂",
    "笑死": "😂💀",
    "牛逼": "🔥💪",
    "nb": "🔥💪",
    "666": "🔥",
    "晚安": "🌙✨",
}


async def handle_trigger(update: Update, context: ContextTypes.DEFAULT_TYPE):
    """关键词触发气氛组"""
    msg = update.effective_message
    if not msg or not msg.text:
        return

    text = msg.text.strip()
    for keyword, emoji in TRIGGER_REACTIONS.items():
        if text == keyword or text.startswith(keyword):
            try:
                await msg.react(emoji)
            except Exception:
                pass
            break


async def cmd_checkin(update: Update, context: ContextTypes.DEFAULT_TYPE):
    """每日签到"""
    user = update.effective_user
    result = await daily_checkin(update.effective_chat.id, user.id, user.username or user.first_name)
    if result["ok"]:
        reply = await update.message.reply_text(
            f"✅ 签到成功！\n"
            f"📊 积分: {result['score']}\n"
            f"🔥 连续签到: {result['streak']} 天\n"
            f"🎁 签到奖励: +{result['bonus']} 分（基础 {result.get('base', 0)} + 连签 {result.get('streak_bonus', 0)}）"
        )
    else:
        reply = await update.message.reply_text("❌ 你今天已经签到过了")
    asyncio.create_task(auto_delete(update.message, seconds=60))
    await record_bot_message(reply)
    asyncio.create_task(auto_delete(reply, seconds=60))


async def cmd_trivia(update: Update, context: ContextTypes.DEFAULT_TYPE):
    """收割机知识答题"""
    q = await get_trivia_question()
    text = f"❓ {q['q']}\n\n"
    for i, opt in enumerate(q["opts"], 1):
        text += f"{i}. {opt}\n"
    text += f"\n💡 请回复序号或答案文字"
    context.user_data["trivia_answer"] = q["a"]
    context.user_data["trivia_options"] = q["opts"]
    reply = await update.message.reply_text(text)
    asyncio.create_task(auto_delete(update.message, seconds=60))
    await record_bot_message(reply)
    asyncio.create_task(auto_delete(reply, seconds=60))


async def cmd_score(update: Update, context: ContextTypes.DEFAULT_TYPE):
    """查看积分"""
    from db.models import GameScore
    user = update.effective_user
    scores = await GameScore.filter(user_id=user.id).all()
    if not scores:
        reply = await update.message.reply_text("📊 你还没有积分记录\n💡 签到 /checkin 或答题 /trivia 开始赚积分")
    else:
        text = "📊 你的积分\n━━━━━━━━━━━━\n"
        for s in scores:
            text += f"🎮 {s.game_type}: {s.score} 分 (胜率 {s.wins}/{s.total})\n"
        reply = await update.message.reply_text(text)
    asyncio.create_task(auto_delete(update.message, seconds=60))
    await record_bot_message(reply)
    asyncio.create_task(auto_delete(reply, seconds=60))


async def cmd_rank(update: Update, context: ContextTypes.DEFAULT_TYPE):
    """排行榜"""
    top = await get_leaderboard(update.effective_chat.id, "trivia", 10)
    if not top:
        reply = await update.message.reply_text("🏆 暂无排行数据")
    else:
        text = "🏆 知识答题排行榜\n━━━━━━━━━━━━━━━━━━\n"
        medals = ["🥇", "🥈", "🥉"]
        for i, s in enumerate(top):
            medal = medals[i] if i < 3 else f" {i+1}."
            text += f"{medal} @{s.username or s.user_id} — {s.score} 分\n"
        reply = await update.message.reply_text(text)
    asyncio.create_task(auto_delete(update.message, seconds=60))
    await record_bot_message(reply)
    asyncio.create_task(auto_delete(reply, seconds=60))


async def build_lottery_text(event, count: int | None = None) -> str:
    if count is None:
        count = await count_lottery_participants(event.id)
    return (
        "🎁 群内抽奖\n"
        "━━━━━━━━━━━━\n"
        f"🏷️ 标题：{event.title or event.prize}\n"
        f"🎯 奖品：{event.prize}\n"
        f"👤 发起人：@{event.creator_name or event.creator_id}\n"
        + (f"📝 描述：{event.description}\n" if getattr(event, "description", None) else "")
        + f"✅ 参与条件：{await lottery_condition_text(event)}\n"
        f"⏱️ 结束条件：{await lottery_end_text(event)}\n"
        f"👥 当前参与：{count} 人\n\n"
        "点击下方按钮参与抽奖。"
    )


def lottery_keyboard(event_id: int) -> InlineKeyboardMarkup:
    return InlineKeyboardMarkup([[InlineKeyboardButton("🎁 参与抽奖", callback_data=f"lottery:join:{event_id}")]])


async def schedule_lottery_draw(context: ContextTypes.DEFAULT_TYPE, event_id: int, seconds: int):
    async def _run():
        try:
            await asyncio.sleep(seconds)
            result = await draw_lottery_event(event_id)
            event = result.get("event")
            if not event or not event.message_id:
                return
            if result.get("ok"):
                winner = result["winner"]
                text = (
                    "🎉 抽奖已开奖\n"
                    "━━━━━━━━━━━━\n"
                    f"🏷️ 标题：{event.title or event.prize}\n"
        f"🎯 奖品：{event.prize}\n"
                    f"👥 参与人数：{result['count']} 人\n"
                    f"🏆 中奖用户：@{winner.username or winner.first_name or winner.user_id}"
                )
            else:
                text = f"🎁 抽奖已结束\n━━━━━━━━━━━━\n🎯 奖品：{event.prize}\n❌ {result.get('reason', '未开奖')}"
            await context.bot.edit_message_text(chat_id=event.chat_id, message_id=event.message_id, text=text)
        except Exception as e:
            logger.warning(f"⚠️ 自动开奖失败: {type(e).__name__}: {e}")
    asyncio.create_task(_run())


async def create_lottery_from_text(update: Update, context: ContextTypes.DEFAULT_TYPE, spec_text: str, publish_chat_id: int | None = None):
    user = update.effective_user
    msg = update.effective_message
    spec = parse_lottery_spec(spec_text)
    target_chat_id = publish_chat_id or msg.chat_id
    event = await create_lottery_event(
        chat_id=target_chat_id,
        creator_id=user.id,
        creator_name=user.username or user.first_name or str(user.id),
        spec=spec,
    )
    lottery_text = await build_lottery_text(event)
    sent = await context.bot.send_message(
        chat_id=target_chat_id,
        text=lottery_text,
        reply_markup=lottery_keyboard(event.id),
    )
    await record_bot_message(sent, lottery_text)
    event.message_id = sent.message_id
    await event.save()
    if event.draw_type == "time" or event.end_type in {"minutes", "time"}:
        await schedule_lottery_draw(context, event.id, event.end_value * 60)
    return event


async def send_lottery_private入口(update: Update, context: ContextTypes.DEFAULT_TYPE):
    me = await context.bot.get_me()
    bot_username = me.username
    target_chat_id = update.effective_chat.id
    url = f"https://t.me/{bot_username}?start=lottery_{target_chat_id}"
    keyboard = InlineKeyboardMarkup([[InlineKeyboardButton("去私聊设置抽奖", url=url)]])
    text = (
        "🎁 发起群内抽奖\n"
        "为了避免奖品和条件刷屏，请到 Bot 私聊界面设置。\n\n"
        f"👉 点击进入：{url}"
    )
    reply = await update.effective_message.reply_text(text, reply_markup=keyboard, disable_web_page_preview=True)
    asyncio.create_task(auto_delete(update.effective_message, seconds=60))
    await record_bot_message(reply)
    asyncio.create_task(auto_delete(reply, seconds=60))
    return reply


async def cmd_lottery(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if update.effective_chat.type != "private":
        await send_lottery_private入口(update, context)
        return

    context.user_data["awaiting_lottery_spec"] = True
    context.user_data["lottery_target_chat_id"] = config.TG_CHAT_ID
    reply = await update.message.reply_text(
        "🎁 发起群内抽奖\n"
        "请发送：奖品 | 参与条件 | 结束条件\n\n"
        "示例：月卡一张 | all | people:3\n"
        "参与条件：all / checkin / points:N\n"
        "结束条件：people:N / minutes:N"
    )
    await record_bot_message(reply)


async def cmd_shop(update: Update, context: ContextTypes.DEFAULT_TYPE):
    user = update.effective_user
    summary = await get_scores_summary(user.id, query.message.chat_id)
    text = "🛒 积分商城\n━━━━━━━━━━━━\n"
    text += f"📊 当前总积分：{summary['total']} 分\n\n"
    for item_id, item in SHOP_ITEMS.items():
        text += f"{item_id}. {item['name']} — {item['cost']} 分\n   {item['desc']}\n"
    text += "\n购买：/buy 商品编号，例如 /buy 1"
    reply = await update.message.reply_text(text)
    asyncio.create_task(auto_delete(update.message, seconds=60))
    await record_bot_message(reply)
    asyncio.create_task(auto_delete(reply, seconds=60))


async def cmd_buy(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if not context.args:
        reply = await update.message.reply_text("用法：/buy 商品编号，例如 /buy 1")
    else:
        result = await buy_shop_item(update.effective_chat.id, update.effective_user.id, context.args[0], update.effective_user.username or update.effective_user.first_name or str(update.effective_user.id))
        if result["ok"]:
            item = result["item"]
            await Action.create(action="SHOP_BUY", chat_id=update.effective_chat.id, user_id=update.effective_user.id, username=update.effective_user.username, details={"item": item, "chat_id": update.effective_chat.id})
            reply = await update.message.reply_text(f"✅ 兑换成功：{item['name']}\n📊 剩余总积分：{result['total']} 分")
        else:
            item = result.get("item")
            extra = f"，需要 {item['cost']} 分" if item else ""
            reply = await update.message.reply_text(f"❌ 兑换失败：{result['reason']}{extra}")
    asyncio.create_task(auto_delete(update.message, seconds=60))
    await record_bot_message(reply)
    asyncio.create_task(auto_delete(reply, seconds=60))


async def cmd_panel(update: Update, context: ContextTypes.DEFAULT_TYPE):
    reply = await update.message.reply_text(
        "🎛️ 操作面板\n请选择要执行的操作：\n\n⏱️ 60 秒无操作后自动消失。",
        reply_markup=panel_keyboard(),
    )
    asyncio.create_task(auto_delete(update.message, seconds=60))
    schedule_panel_idle_delete(context, reply)

async def handle_panel_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    await query.answer()
    user = query.from_user
    action = query.data.split(":", 1)[1]
    if action == "checkin":
        result = await daily_checkin(query.message.chat_id, user.id, user.username or user.first_name or str(user.id))
        text = "❌ 你今天已经签到过了" if not result["ok"] else f"✅ 签到成功！奖励 +{result['bonus']} 分，连续 {result['streak']} 天"
    elif action == "lottery":
        me = await context.bot.get_me()
        url = f"https://t.me/{me.username}?start=lottery_{query.message.chat_id}"
        keyboard = InlineKeyboardMarkup([[InlineKeyboardButton("去私聊设置抽奖", url=url)]])
        await query.edit_message_text(
            "🎁 发起群内抽奖\n"
            "请到 Bot 私聊界面设置奖品、参与条件和结束条件。\n\n"
            f"👉 点击进入：{url}\n\n"
            "⏱️ 60 秒无操作后自动消失。",
            reply_markup=keyboard,
            disable_web_page_preview=True,
        )
        schedule_panel_idle_delete(context, query.message)
        return
    elif action == "shop":
        summary = await get_scores_summary(user.id, query.message.chat_id)
        text = f"🛒 积分商城\n当前总积分：{summary['total']} 分\n" + "\n".join([f"{v['item_key']}. {v['name']} — {v['cost']} 分" for v in await list_shop_items(query.message.chat_id)]) + "\n\n购买请发送 /buy 商品编号"
    elif action == "me":
        summary = await get_scores_summary(user.id, query.message.chat_id)
        text = f"👤 我的积分\n总积分：{summary['total']} 分\n" + "\n".join([f"{s.game_type}: {s.score} 分" for s in summary['scores']])
    else:
        text = "📖 常用：/me /checkin /trivia /lottery /shop /panel"
    await query.edit_message_text(
        text + "\n\n⏱️ 60 秒无操作后自动消失。",
        reply_markup=panel_keyboard(),
    )
    schedule_panel_idle_delete(context, query.message)


async def handle_trivia_answer(update: Update, context: ContextTypes.DEFAULT_TYPE):
    """处理 /trivia 后的用户答题。"""
    msg = update.effective_message
    user = update.effective_user
    if not msg or not msg.text or not user or user.is_bot:
        return


    correct_answer = context.user_data.get("trivia_answer")
    options = context.user_data.get("trivia_options") or []
    if not correct_answer:
        return

    raw_answer = msg.text.strip()
    answer = raw_answer
    if raw_answer.isdigit():
        idx = int(raw_answer) - 1
        if 0 <= idx < len(options):
            answer = options[idx]

    result = await check_trivia_answer(update.effective_chat.id, user.id, user.username or user.first_name or str(user.id), answer, correct_answer)
    context.user_data.pop("trivia_answer", None)
    context.user_data.pop("trivia_options", None)

    if result["correct"]:
        text = (
            "✅ 回答正确！\n"
            f"🎯 正确答案：{correct_answer}\n"
            f"📊 当前积分：{result['score']}\n"
            f"🔥 连击：{result['streak']}"
        )
    else:
        text = (
            "❌ 回答错误\n"
            f"🎯 正确答案：{correct_answer}\n"
            f"📊 当前积分：{result['score']}"
        )
    reply = await msg.reply_text(text)
    asyncio.create_task(auto_delete(msg, seconds=60))
    await record_bot_message(reply)
    asyncio.create_task(auto_delete(reply, seconds=60))
    raise ApplicationHandlerStop


async def handle_lottery_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    await query.answer()
    parts = query.data.split(":")
    event_id = int(parts[-1])
    user = query.from_user
    result = await join_lottery_event(event_id, user.id, user.username or "", user.first_name or "")
    if not result["ok"]:
        await query.answer(result["reason"], show_alert=True)
        return
    event = result["event"]
    if result["should_draw"]:
        draw = await draw_lottery_event(event.id)
        if draw.get("ok"):
            winner = draw["winner"]
            text = (
                "🎉 抽奖已开奖\n"
                "━━━━━━━━━━━━\n"
                f"🏷️ 标题：{event.title or event.prize}\n"
        f"🎯 奖品：{event.prize}\n"
                f"👥 参与人数：{draw['count']} 人\n"
                f"🏆 中奖用户：@{winner.username or winner.first_name or winner.user_id}"
            )
            await query.edit_message_text(text)
        else:
            await query.edit_message_text(f"🎁 抽奖已结束\n❌ {draw.get('reason', '未开奖')}")
    else:
        await query.edit_message_text(await build_lottery_text(event, result["count"]), reply_markup=lottery_keyboard(event.id))
        await query.answer(f"参与成功，当前 {result['count']} 人")


async def cmd_lottery_start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if update.effective_chat.type != "private" or not context.args:
        return
    arg = context.args[0]
    if not arg.startswith("lottery_"):
        return
    try:
        target_chat_id = int(arg.split("_", 1)[1])
    except Exception:
        target_chat_id = config.TG_CHAT_ID
    context.user_data["awaiting_lottery_spec"] = True
    context.user_data["lottery_target_chat_id"] = target_chat_id
    reply = await update.message.reply_text(
        "🎁 发起群内抽奖\n"
        "请发送：奖品 | 参与条件 | 结束条件\n\n"
        "示例：月卡一张 | all | people:3\n"
        "参与条件：all / checkin / points:N\n"
        "结束条件：people:N / minutes:N"
    )


async def handle_private_lottery_text(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if update.effective_chat.type != "private" or not context.user_data.get("awaiting_lottery_spec"):
        return
    try:
        target_chat_id = int(context.user_data.get("lottery_target_chat_id") or config.TG_CHAT_ID)
        event = await create_lottery_from_text(update, context, update.message.text.strip(), publish_chat_id=target_chat_id)
        context.user_data.pop("awaiting_lottery_spec", None)
        context.user_data.pop("lottery_target_chat_id", None)
        await update.message.reply_text(
            "✅ 抽奖活动已发布到群里\n"
            f"🏷️ 标题：{event.title or event.prize}\n"
        f"🎯 奖品：{event.prize}\n"
            f"✅ 参与条件：{await lottery_condition_text(event)}\n"
            f"⏱️ 结束条件：{await lottery_end_text(event)}"
        )
    except Exception as e:
        await update.message.reply_text(
            f"❌ 抽奖格式错误：{e}\n\n"
            "请重新发送：奖品 | 参与条件 | 结束条件\n"
            "示例：月卡一张 | all | people:3"
        )


async def auto_delete(message, seconds=60):
    try:
        await asyncio.sleep(seconds)
        await message.delete()
    except Exception:
        pass


def register_fun(app):
    app.add_handler(CommandHandler("checkin", cmd_checkin, filters.ChatType.GROUPS))
    app.add_handler(CommandHandler("trivia", cmd_trivia, filters.ChatType.GROUPS))
    app.add_handler(CommandHandler("score", cmd_score, filters.ChatType.GROUPS))
    app.add_handler(CommandHandler("rank", cmd_rank, filters.ChatType.GROUPS))
    app.add_handler(CommandHandler("lottery", cmd_lottery))
    app.add_handler(CommandHandler("shop", cmd_shop, filters.ChatType.GROUPS))
    app.add_handler(CommandHandler("buy", cmd_buy, filters.ChatType.GROUPS))
    app.add_handler(CommandHandler("panel", cmd_panel, filters.ChatType.GROUPS))
    app.add_handler(CommandHandler("start", cmd_lottery_start, filters.ChatType.PRIVATE), group=1)
    app.add_handler(CallbackQueryHandler(handle_panel_callback, pattern=r"^panel:"))
    app.add_handler(CallbackQueryHandler(handle_lottery_callback, pattern=r"^lottery:"))
    app.add_handler(MessageHandler(filters.TEXT & filters.ChatType.PRIVATE & ~filters.COMMAND, handle_private_lottery_text), group=1)
    app.add_handler(MessageHandler(filters.TEXT & filters.ChatType.GROUPS & ~filters.COMMAND, handle_trivia_answer), group=-1)
    app.add_handler(MessageHandler(filters.TEXT & filters.ChatType.GROUPS, handle_trigger), group=2)
