<?php

/**
 * 文件功能：赛马竞猜前台控制器
 *
 * 提供用户在聊天室内参与赛马的 API 接口：
 * - 查询当前场次信息（马匹、注池、赔率）
 * - 提交下注（扣除金币 + 写入下注记录）
 * - 查询本人下注状态
 * - 查询最近历史记录
 *
 * @author  ChatRoom Laravel
 *
 * @version 1.0.0
 */

namespace App\Http\Controllers;

use App\Enums\CurrencySource;
use App\Events\MessageSent;
use App\Jobs\SaveMessageJob;
use App\Models\GameConfig;
use App\Models\HorseBet;
use App\Models\HorseRace;
use App\Services\ChatStateService;
use App\Services\UserCurrencyService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class HorseRaceController extends Controller
{
    public function __construct(
        private readonly UserCurrencyService $currency,
    ) {}

    /**
     * 获取当前进行中的场次信息（前端轮询或事件触发后调用）。
     */
    public function currentRace(Request $request): JsonResponse
    {
        $user = $request->user();
        if (! $user) {
            return response()->json(['message' => '未登录', 'status' => 'error'], 401);
        }

        $race = HorseRace::currentRace();

        if (! $race) {
            return response()->json([
                'race' => null,
                // 即使当前无赛马场次，也返回最新金币余额，供前端打开弹窗时刷新显示。
                'jjb' => (int) ($user->jjb ?? 0),
            ]);
        }

        $myBet = HorseBet::query()
            ->where('race_id', $race->id)
            ->where('user_id', $user->id)
            ->first();

        // 计算各马匹当前注额
        $config = GameConfig::forGame('horse_racing')?->params ?? [];
        $houseTake = (int) ($config['house_take_percent'] ?? 5);
        $seedPool = (int) ($config['seed_pool'] ?? 0);

        $horsePools = HorseBet::query()
            ->where('race_id', $race->id)
            ->groupBy('horse_id')
            ->selectRaw('horse_id, SUM(amount) as pool')
            ->pluck('pool', 'horse_id')
            ->toArray();

        $oddsMap = HorseRace::calcOdds($horsePools, $houseTake, $seedPool);

        // 计算实时赔率
        $horses = $this->normalizeRaceHorses($race->horses);
        $horsesWithBets = array_map(function (array $horse) use ($horsePools, $oddsMap) {
            $horseId = (int) $horse['id'];
            $horsePool = (int) ($horsePools[$horseId] ?? 0);
            $odds = $horsePool > 0 ? ($oddsMap[$horseId] ?? null) : null;

            return [
                'id' => $horseId,
                'name' => (string) $horse['name'],
                'emoji' => (string) $horse['emoji'],
                'pool' => $horsePool,
                'odds' => $odds,
            ];
        }, $horses);

        // 押注阶段实时总池 = 当前记录的基础池（通常为种子池）+ 实时下注总额；
        // 跑马/结算阶段 total_pool 已写回最终值，不能再重复叠加下注额。
        $basePool = $race->status === 'betting'
            ? max((int) $race->total_pool, $seedPool)
            : (int) $race->total_pool;
        $displayTotalPool = $race->status === 'betting'
            ? $basePool + array_sum(array_values($horsePools))
            : $basePool;

        $minBet = (int) ($config['min_bet'] ?? 100);
        $maxBet = (int) ($config['max_bet'] ?? 100000);

        return response()->json([
            'race' => [
                'id' => $race->id,
                'status' => $race->status,
                'bet_closes_at' => $race->bet_closes_at?->toIso8601String(),
                'seconds_left' => $race->status === 'betting'
                    ? max(0, (int) now()->diffInSeconds($race->bet_closes_at, false))
                    : 0,
                'horses' => $horsesWithBets,
                'total_pool' => $displayTotalPool,
                'min_bet' => $minBet,
                'max_bet' => $maxBet,
                'my_bet' => $myBet ? [
                    'horse_id' => $myBet->horse_id,
                    'amount' => $myBet->amount,
                ] : null,
            ],
            // 返回当前用户最新金币，确保弹窗右上角余额每次打开都以服务端最新值为准。
            'jjb' => (int) ($user->jjb ?? 0),
        ]);
    }

    /**
     * 用户提交下注。
     *
     * 同一场每人限下一注，下注成功后立即扣除金币。
     */
    public function bet(Request $request): JsonResponse
    {
        if (! GameConfig::isEnabled('horse_racing')) {
            return response()->json(['ok' => false, 'message' => '赛马竞猜当前未开启。']);
        }

        $data = $request->validate([
            'race_id' => 'required|integer|exists:horse_races,id',
            'horse_id' => 'required|integer|min:1',
            'amount' => 'required|integer|min:1',
        ]);

        $config = GameConfig::forGame('horse_racing')?->params ?? [];
        $minBet = (int) ($config['min_bet'] ?? 100);
        $maxBet = (int) ($config['max_bet'] ?? 100000);

        if ($data['amount'] < $minBet || $data['amount'] > $maxBet) {
            return response()->json(['ok' => false, 'message' => "押注金额须在 {$minBet}~{$maxBet} 金币之间。"]);
        }

        $race = HorseRace::find($data['race_id']);

        if (! $race || ! $race->isBettingOpen()) {
            return response()->json(['ok' => false, 'message' => '当前不在下注时间内。']);
        }

        // 验证马匹 ID 是否有效
        $horses = $this->normalizeRaceHorses($race->horses);
        $validIds = array_column($horses, 'id');
        if (! in_array($data['horse_id'], $validIds, true)) {
            return response()->json(['ok' => false, 'message' => '无效的马匹编号。']);
        }

        $user = $request->user();
        $currency = $this->currency;

        // 校验余额
        if (($user->jjb ?? 0) < $data['amount']) {
            return response()->json(['ok' => false, 'message' => '金币不足，无法下注。']);
        }

        return DB::transaction(function () use ($user, $race, $data, $currency, $horses): JsonResponse {
            // 幂等：同一场只能下一注
            $existing = HorseBet::query()
                ->where('race_id', $race->id)
                ->where('user_id', $user->id)
                ->lockForUpdate()
                ->exists();

            if ($existing) {
                return response()->json(['ok' => false, 'message' => '本场您已下注，请等待开奖。']);
            }

            // 找出马匹名称
            $horseName = '';
            $horseName = $this->resolveHorseDisplayName($horses, (int) $data['horse_id']);

            // 扣除金币
            $currency->change(
                $user,
                'gold',
                -$data['amount'],
                CurrencySource::HORSE_BET,
                "赛马 #{$race->id} 押注 {$horseName}",
            );

            // 写入下注记录
            HorseBet::create([
                'race_id' => $race->id,
                'user_id' => $user->id,
                'horse_id' => $data['horse_id'],
                'amount' => $data['amount'],
                'status' => 'pending',
            ]);

            $chatState = app(ChatStateService::class);
            $formattedAmount = number_format($data['amount']);
            $content = "🐎 <b>【赛马】【{$user->username}】</b> 押注了 <b>{$formattedAmount}</b> 金币（{$horseName}）！✨";
            $msg = [
                'id' => $chatState->nextMessageId(1),
                'room_id' => 1,
                'from_user' => '系统传音',
                'to_user' => '大家',
                'content' => $content,
                'is_secret' => false,
                'font_color' => '#d97706',
                'action' => '',
                'sent_at' => now()->toDateTimeString(),
            ];
            $chatState->pushMessage(1, $msg);
            event(new MessageSent(1, $msg));
            SaveMessageJob::dispatch($msg);

            return response()->json([
                'ok' => true,
                'message' => "✅ 已押注「{$horseName}」{$data['amount']} 金币，等待开跑！",
                'amount' => $data['amount'],
                'horse_id' => $data['horse_id'],
            ]);
        });
    }

    /**
     * 查询最近10场历史记录（前端展示胜负趋势）。
     */
    public function history(): JsonResponse
    {
        $races = HorseRace::query()
            ->where('status', 'settled')
            ->orderByDesc('id')
            ->limit(10)
            ->get(['id', 'horses', 'winner_horse_id', 'total_pool', 'total_bets', 'settled_at']);

        // 转换获胜马匹名称
        $history = $races->map(function ($race) {
            $winnerName = '未知';
            foreach ($this->normalizeRaceHorses($race->horses) as $horse) {
                if ((int) $horse['id'] === (int) $race->winner_horse_id) {
                    $winnerName = (string) $horse['emoji'].(string) $horse['name'];
                    break;
                }
            }

            return [
                'id' => $race->id,
                'winner_id' => $race->winner_horse_id,
                'winner_name' => $winnerName,
                'total_pool' => $race->total_pool,
                'total_bets' => $race->total_bets,
                'settled_at' => $race->settled_at?->toDateTimeString(),
            ];
        });

        return response()->json(['history' => $history]);
    }

    /**
     * 兼容旧赛马数据结构，统一清洗为前端可消费的马匹数组。
     *
     * @return array<int, array{id:int,name:string,emoji:string}>
     */
    private function normalizeRaceHorses(mixed $horses): array
    {
        if (! is_array($horses)) {
            return [];
        }

        $normalizedHorses = [];

        foreach ($horses as $index => $horse) {
            if (! is_array($horse)) {
                continue;
            }

            $horseId = isset($horse['id']) && is_numeric($horse['id'])
                ? (int) $horse['id']
                : $index + 1;
            $horseName = trim((string) ($horse['name'] ?? ''));
            if ($horseName === '') {
                $horseName = '未知马匹';
            }

            $normalizedHorses[] = [
                'id' => $horseId,
                'name' => $horseName,
                'emoji' => (string) ($horse['emoji'] ?? '🐎'),
            ];
        }

        return $normalizedHorses;
    }

    /**
     * 根据马匹编号返回展示名称，供系统播报与下注回执共用。
     *
     * @param  array<int, array{id:int,name:string,emoji:string}>  $horses
     */
    private function resolveHorseDisplayName(array $horses, int $horseId): string
    {
        foreach ($horses as $horse) {
            if ((int) ($horse['id'] ?? 0) === $horseId) {
                return (string) ($horse['emoji'] ?? '🐎').(string) ($horse['name'] ?? '未知马匹');
            }
        }

        return '🐎未知马匹';
    }
}
