<?php

/**
 * 文件功能：赛马跑马动画广播 + 结算队列任务
 *
 * 押注截止后触发，模拟跑马进度并实时广播，
 * 跑完后确定获胜者并调度结算任务。
 *
 * @author  ChatRoom Laravel
 *
 * @version 1.0.0
 */

namespace App\Jobs;

use App\Events\HorseRaceProgress;
use App\Events\MessageSent;
use App\Models\GameConfig;
use App\Models\HorseBet;
use App\Models\HorseRace;
use App\Services\ChatStateService;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;

class RunHorseRaceJob implements ShouldQueue
{
    use Queueable;

    /**
     * 最大重试次数。
     */
    public int $tries = 2;

    /**
     * @param  HorseRace  $race  要运行的场次
     */
    public function __construct(
        public readonly HorseRace $race,
    ) {}

    /**
     * 执行跑马过程并广播进度，最后触发结算。
     */
    public function handle(ChatStateService $chatState): void
    {
        $race = $this->race->fresh();

        // 防止重复执行
        if (! $race || $race->status !== 'betting') {
            return;
        }

        // 乐观锁：CAS 改状态为 running
        $updated = HorseRace::query()
            ->where('id', $race->id)
            ->where('status', 'betting')
            ->update([
                'status' => 'running',
                'race_starts_at' => now(),
            ]);

        if (! $updated) {
            return;
        }

        $race->refresh();

        // 公屏通知：跑马开始
        $horseList = implode(' ', array_map(
            fn ($h) => "{$h['emoji']}{$h['name']}",
            $race->horses ?? []
        ));

        $startMsg = [
            'id' => $chatState->nextMessageId(1),
            'room_id' => 1,
            'from_user' => '系统传音',
            'to_user' => '大家',
            'content' => "🏇 【赛马】第 #{$race->id} 场押注截止！马匹已进入跑道，比赛开始！参赛阵容：{$horseList}",
            'is_secret' => false,
            'font_color' => '#336699',
            'action' => '大声宣告',
            'sent_at' => now()->toDateTimeString(),
        ];
        $chatState->pushMessage(1, $startMsg);
        broadcast(new MessageSent(1, $startMsg));
        SaveMessageJob::dispatch($startMsg);

        $config = GameConfig::forGame('horse_racing')?->params ?? [];
        $raceDuration = (int) ($config['race_duration'] ?? 30);
        $seedPool = (int) ($config['seed_pool'] ?? 0);
        $horses = $race->horses ?? [];
        $horseCount = count($horses);

        // 初始化各马匹进度（0~100），每步随机增量
        $positions = array_fill_keys(array_column($horses, 'id'), 0);
        $speeds = [];
        foreach ($horses as $horse) {
            // 基础速度：随机值，确保比赛有悬念（均值接近 race_duration 步完成）
            $speeds[$horse['id']] = random_int(2, 5);
        }

        // 跑马循环：模拟进度广播（此 job 为同步阻塞广播，每步 sleep 1 秒）
        $step = 0;
        $maxSteps = $raceDuration;
        $winnerId = null;

        while ($step < $maxSteps && $winnerId === null) {
            $step++;

            foreach ($horses as $horse) {
                $horseId = $horse['id'];
                // 随机冲刺（小概率加速）
                $boost = random_int(0, 10) >= 9 ? random_int(5, 15) : 0;
                $positions[$horseId] = min(100, $positions[$horseId] + $speeds[$horseId] + $boost);
            }

            // 检查是否有马到达终点
            $finishedHorses = array_filter($positions, fn ($p) => $p >= 100);
            $finished = ! empty($finishedHorses);

            if ($finished) {
                // 取进度最高的马为冠军（若并列取 id 最小的）
                arsort($finishedHorses);
                $winnerId = (int) array_key_first($finishedHorses);
            }

            // 广播当前帧进度
            broadcast(new HorseRaceProgress($race->id, $positions, $finished, $winnerId ?? $this->leadingHorse($positions)));

            if ($finished) {
                break;
            }

            sleep(1);
        }

        // 如果时间到还没分出胜负，取最高进度的马为赢家
        if ($winnerId === null) {
            arsort($positions);
            $winnerId = (int) array_key_first($positions);
        }

        // 更新场次记录
        $race->update([
            'race_ends_at' => now(),
            'winner_horse_id' => $winnerId,
        ]);

        // 计算注池统计
        $totalBets = HorseBet::query()->where('race_id', $race->id)->count();
        $totalPool = $seedPool + HorseBet::query()->where('race_id', $race->id)->sum('amount');

        $race->update([
            'total_bets' => $totalBets,
            'total_pool' => $totalPool,
        ]);

        // 触发结算任务
        CloseHorseRaceJob::dispatch($race->fresh());
    }

    /**
     * 获取当前领跑马匹 ID（进度最高）。
     *
     * @param  array<int, int>  $positions
     */
    private function leadingHorse(array $positions): int
    {
        arsort($positions);

        return (int) array_key_first($positions);
    }
}
