<?php

/**
 * 文件功能：老虎机游戏前台控制器
 *
 * 提供老虎机转动 API：
 * - 检查游戏开关、每日限制
 * - 扣除金币、生成三列图案
 * - 判断结果、赔付金币、写流水
 * - 三个7时全服公屏广播
 * - 返回结果供前端播放动画
 *
 * @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\SlotMachineLog;
use App\Services\ChatStateService;
use App\Services\UserCurrencyService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

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

    /**
     * 获取老虎机配置信息（图案表、赔率、今日剩余次数）。
     */
    public function info(Request $request): JsonResponse
    {
        if (! GameConfig::isEnabled('slot_machine')) {
            return response()->json(['enabled' => false]);
        }

        $config = GameConfig::forGame('slot_machine')?->params ?? [];
        $user = $request->user();
        $dailyLimit = (int) ($config['daily_limit'] ?? 0);
        $usedToday = 0;

        if ($dailyLimit > 0) {
            $usedToday = SlotMachineLog::query()
                ->where('user_id', $user->id)
                ->whereDate('created_at', today())
                ->count();
        }

        return response()->json([
            'enabled' => true,
            'cost_per_spin' => (int) ($config['cost_per_spin'] ?? 100),
            'daily_limit' => $dailyLimit,
            'used_today' => $usedToday,
            'remaining' => $dailyLimit > 0 ? max(0, $dailyLimit - $usedToday) : null,
            'symbols' => collect(SlotMachineLog::symbols())->map(fn ($s) => $s['emoji']),
        ]);
    }

    /**
     * 执行一次转动。
     *
     * 流程：检查可玩 → 扣费 → 摇号 → 赔付 → 写日志 → 全服广播（三7）→ 返回结果
     */
    public function spin(Request $request): JsonResponse
    {
        if (! GameConfig::isEnabled('slot_machine')) {
            return response()->json(['ok' => false, 'message' => '老虎机未开放。']);
        }

        $config = GameConfig::forGame('slot_machine')?->params ?? [];
        $cost = (int) ($config['cost_per_spin'] ?? 100);
        $dailyLimit = (int) ($config['daily_limit'] ?? 0);

        $user = $request->user();

        // 金币余额检查
        if (($user->jjb ?? 0) < $cost) {
            return response()->json(['ok' => false, 'message' => "金币不足，每次转动需 {$cost} 金币。"]);
        }

        // 每日次数限制检查
        if ($dailyLimit > 0) {
            $usedToday = SlotMachineLog::query()
                ->where('user_id', $user->id)
                ->whereDate('created_at', today())
                ->count();

            if ($usedToday >= $dailyLimit) {
                return response()->json(['ok' => false, 'message' => "今日已转动 {$dailyLimit} 次，明日再来！"]);
            }
        }

        return DB::transaction(function () use ($user, $cost, $config): JsonResponse {
            // ① 扣费
            $this->currency->change(
                $user,
                'gold',
                -$cost,
                CurrencySource::SLOT_SPIN,
                '老虎机转动消耗',
            );

            // ② 摇号
            $r1 = SlotMachineLog::randomSymbol();
            $r2 = SlotMachineLog::randomSymbol();
            $r3 = SlotMachineLog::randomSymbol();

            $resultType = SlotMachineLog::judgeResult($r1, $r2, $r3);
            $symbols = SlotMachineLog::symbols();

            // ③ 计算赔付金额
            $payout = $this->calcPayout($resultType, $cost, $config);

            // ④ 赔付金币
            if ($payout > 0) {
                $this->currency->change(
                    $user,
                    'gold',
                    $payout,
                    CurrencySource::SLOT_WIN,
                    "老虎机 {$resultType} 中奖",
                );
            } elseif ($resultType === 'curse' && ($config['curse_enabled'] ?? true)) {
                // 诅咒：再扣一倍本金
                $cursePenalty = $cost;
                if (($user->jjb ?? 0) >= $cursePenalty) {
                    $this->currency->change(
                        $user,
                        'gold',
                        -$cursePenalty,
                        CurrencySource::SLOT_CURSE,
                        '老虎机三骷髅诅咒额外扣除',
                    );
                    $payout = -$cursePenalty; // 净损失 = 本金+惩罚
                }
            }

            // ⑤ 写游戏日志
            $resultLabel = SlotMachineLog::resultLabel($resultType);
            SlotMachineLog::create([
                'user_id' => $user->id,
                'reel1' => $r1,
                'reel2' => $r2,
                'reel3' => $r3,
                'result_type' => $resultType,
                'cost' => $cost,
                'payout' => $payout,
            ]);

            // ⑥ 广播通知
            $e1 = $symbols[$r1]['emoji'];
            $e2 = $symbols[$r2]['emoji'];
            $e3 = $symbols[$r3]['emoji'];

            if ($resultType === 'jackpot') {
                // 三个7：全服公屏广播
                $this->broadcastJackpot($user->username, $payout, $cost);
            } elseif (in_array($resultType, ['triple_gem', 'triple', 'pair'], true)) {
                // 普通中奖：仅向本人发送聊天室系统通知
                $net = $payout - $cost;
                $content = "🎰 {$resultLabel}！{$e1}{$e2}{$e3} 赢得 +💰".number_format($net).' 金币';
                $this->broadcastPersonal($user->username, $content);
            } elseif ($resultType === 'curse') {
                // 诅咒：通知本人
                $content = "☠️ 三骷髅诅咒！{$e1}{$e2}{$e3} 额外扣除 💰".number_format($cost).' 金币！';
                $this->broadcastPersonal($user->username, $content);
            }

            $user->refresh();

            return response()->json([
                'ok' => true,
                'reels' => [$r1, $r2, $r3],
                'emojis' => [
                    $symbols[$r1]['emoji'],
                    $symbols[$r2]['emoji'],
                    $symbols[$r3]['emoji'],
                ],
                'result_type' => $resultType,
                'result_label' => SlotMachineLog::resultLabel($resultType),
                'payout' => $payout,        // 净变化（正=赢，负=额外亏）
                'net_change' => $payout - $cost, // 相对本金的盈亏（debug 用）
                'balance' => $user->jjb ?? 0,
            ]);
        });
    }

    /**
     * 查询最近10条个人记录。
     */
    public function history(Request $request): JsonResponse
    {
        $logs = SlotMachineLog::query()
            ->where('user_id', $request->user()->id)
            ->orderByDesc('id')
            ->limit(10)
            ->get(['id', 'reel1', 'reel2', 'reel3', 'result_type', 'cost', 'payout', 'created_at']);

        $symbols = SlotMachineLog::symbols();

        return response()->json([
            'history' => $logs->map(fn ($l) => [
                'emojis' => [$symbols[$l->reel1]['emoji'], $symbols[$l->reel2]['emoji'], $symbols[$l->reel3]['emoji']],
                'result_label' => SlotMachineLog::resultLabel($l->result_type),
                'payout' => $l->payout,
                'created_at' => $l->created_at->format('H:i'),
            ]),
        ]);
    }

    /**
     * 计算赔付金额（赢时返还 = 本金 × 赔率）。
     *
     * @return int 正数=赢得金额（含本金返还），0=不赔付
     */
    private function calcPayout(string $resultType, int $cost, array $config): int
    {
        $multiplier = match ($resultType) {
            'jackpot' => (int) ($config['jackpot_payout'] ?? 100),
            'triple_gem' => (int) ($config['triple_payout'] ?? 50),
            'triple' => (int) ($config['same_payout'] ?? 10),
            'pair' => (int) ($config['pair_payout'] ?? 2),
            default => 0,
        };

        return $multiplier > 0 ? $cost * $multiplier : 0;
    }

    /**
     * 三个7全服公屏广播。
     */
    private function broadcastJackpot(string $username, int $payout, int $cost): void
    {
        $net = $payout - $cost;
        $content = "🎰🎉【老虎机大奖】恭喜 【{$username}】 转出三个7️⃣！"
            .'狂揽 💰'.number_format($net).' 金币！全服见证奇迹！';

        $msg = [
            'id' => $this->chatState->nextMessageId(1),
            'room_id' => 1,
            'from_user' => '系统传音',
            'to_user' => '大家',
            'content' => $content,
            'is_secret' => false,
            'font_color' => '#f59e0b',
            'action' => '大声宣告',
            'sent_at' => now()->toDateTimeString(),
        ];

        $this->chatState->pushMessage(1, $msg);
        broadcast(new MessageSent(1, $msg));
        SaveMessageJob::dispatch($msg);
    }

    /**
     * 向特定用户发送聊天室私人系统通知（仅该用户可见）。
     *
     * @param  string  $toUsername  接收用户名
     * @param  string  $content  消息内容
     */
    private function broadcastPersonal(string $toUsername, string $content): void
    {
        $msg = [
            'id' => $this->chatState->nextMessageId(1),
            'room_id' => 1,
            'from_user' => '系统传音',
            'to_user' => $toUsername,
            'content' => $content,
            'is_secret' => true,
            'font_color' => '#f59e0b',
            'action' => '',
            'sent_at' => now()->toDateTimeString(),
        ];

        broadcast(new MessageSent(1, $msg));
        SaveMessageJob::dispatch($msg);
    }
}
