from nonebot import on_command
from nonebot.adapters.onebot.v11 import Bot, Event
from .shared import (
    room_store, points_service, config, logger,
    get_scope, check_access, get_event_id,
    _resolve_horse_selector, _format_horse_label,
    _get_horses_in_order, _find_user_horse,
    calculate_odds,
)
from ..models import RoomState, Bet

cancel_cmd = on_command("赛马取消报名", priority=5)


@cancel_cmd.handle()
async def handle_cancel(bot: Bot, event: Event):
    """Handle cancel registration."""
    if not await check_access(bot, event):
        await cancel_cmd.finish("无权限访问此功能")
        return

    scope = get_scope(event)
    user_id = get_event_id(event)
    lock = room_store.get_lock(scope)

    async with lock:
        room = room_store.get_room(scope)
        if not room:
            await cancel_cmd.finish("房间不存在")
            return

        if room.state != RoomState.WAITING:
            await cancel_cmd.finish("比赛正在进行中，无法取消报名")
            return

        user_horse = _find_user_horse(room, user_id)
        if not user_horse:
            await cancel_cmd.finish("你还没有报名")
            return

        bets_to_refund = [b for b in room.bets if b.horse_name == user_horse.name]
        for bet in bets_to_refund:
            await points_service.refund_bet_points(bet.user_id, bet.amount, "取消报名退还下注")
        room.bets = [b for b in room.bets if b.horse_name != user_horse.name]

        del room.horses[user_horse.name]

    await cancel_cmd.finish(f"已取消报名，{_format_horse_label(user_horse)} 已退出")


bet_cmd = on_command("赛马下注", priority=5)


cancel_bet_cmd = on_command("赛马取消下注", priority=5)


@cancel_bet_cmd.handle()
async def handle_cancel_bet(bot: Bot, event: Event):
    """Handle cancel bet - refund all bets placed by the user in current room."""
    if not await check_access(bot, event):
        await cancel_bet_cmd.finish("无权限访问此功能")
        return

    scope = get_scope(event)
    user_id = get_event_id(event)
    lock = room_store.get_lock(scope)

    async with lock:
        room = room_store.get_room(scope)
        if not room:
            await cancel_bet_cmd.finish("房间不存在")
            return

        if room.state != RoomState.WAITING:
            await cancel_bet_cmd.finish("比赛已开始，无法取消下注")
            return

        user_bets = [b for b in room.bets if b.user_id == user_id]
        if not user_bets:
            await cancel_bet_cmd.finish("你还没有下注")
            return

        total_refund = 0
        refund_errors = []
        for bet in user_bets:
            try:
                await points_service.refund_bet_points(bet.user_id, bet.amount, "取消下注退还")
                total_refund += bet.amount
            except Exception as e:
                logger.error(f"退还下注失败 user={bet.user_id} amount={bet.amount}: {e}")
                refund_errors.append(bet)

        if refund_errors:
            failed_amount = sum(b.amount for b in refund_errors)
            room.bets = [b for b in room.bets if b.user_id != user_id or b in refund_errors]
            await cancel_bet_cmd.finish(f"退还部分失败：成功退还 {total_refund} 积分，{len(refund_errors)} 笔退还失败（{failed_amount} 积分），请联系管理员")
            return
        else:
            room.bets = [b for b in room.bets if b.user_id != user_id]

    await cancel_bet_cmd.finish(f"已取消 {len(user_bets)} 笔下注，退还 {total_refund} 积分")


@bet_cmd.handle()
async def handle_bet(bot: Bot, event: Event):
    """Handle bet placement."""
    if not await check_access(bot, event):
        await bet_cmd.finish("无权限访问此功能")
        return

    msg = str(event.get_message()).strip()
    parts = msg.split()
    if len(parts) < 3:
        await bet_cmd.finish("请使用：/赛马下注 <序号|马匹名> <金额>")
        return

    horse_selector = parts[1]
    try:
        amount = int(parts[2])
    except ValueError:
        await bet_cmd.finish("金额必须是正整数")
        return

    if amount < config.MIN_BET:
        await bet_cmd.finish(f"最低下注金额为 {config.MIN_BET}")
        return

    scope = get_scope(event)
    user_id = get_event_id(event)
    lock = room_store.get_lock(scope)

    async with lock:
        room = room_store.get_room(scope)
        if not room:
            await bet_cmd.finish("房间不存在，请先报名")
            return

        if room.state != RoomState.WAITING:
            await bet_cmd.finish("比赛正在进行中，无法下注")
            return

        horse = _resolve_horse_selector(room, horse_selector)
        if not horse:
            await bet_cmd.finish(f"马匹序号/名称 \"{horse_selector}\" 不存在")
            return

        success, balance = await points_service.spend_bet_points(user_id, amount, f"下注 {_format_horse_label(horse)}")
        if not success:
            await bet_cmd.finish(f"积分不足（当前余额：{balance}）")
            return

        room.bets.append(Bet(user_id=user_id, horse_name=horse.name, amount=amount))
        odds = calculate_odds(room)
        await bet_cmd.finish(f"下注成功！{_format_horse_label(horse)} {amount}积分（当前赔率：{odds.get(horse.name, config.MIN_ODDS):.2f}）")


odds_cmd = on_command("赛马赔率", priority=5)


@odds_cmd.handle()
async def handle_odds(bot: Bot, event: Event):
    """Handle odds display."""
    if not await check_access(bot, event):
        await odds_cmd.finish("无权限访问此功能")
        return

    scope = get_scope(event)
    room = room_store.get_room(scope)
    if not room:
        await odds_cmd.finish("房间不存在，请先报名")
        return

    if not room.horses:
        await odds_cmd.finish("还没有马匹报名")
        return

    odds = calculate_odds(room)
    lines = ["当前赔率："]
    total_bet = sum(b.amount for b in room.bets)
    for horse in _get_horses_in_order(room):
        odd = odds.get(horse.name, config.MIN_ODDS)
        horse_bet = sum(b.amount for b in room.bets if b.horse_name == horse.name)
        lines.append(f"  {_format_horse_label(horse)} - {odd:.2f}倍 (总下注: {horse_bet})")
    lines.append(f"总下注池: {total_bet}")

    await odds_cmd.finish("\n".join(lines))
