<?php

/**
 * 文件功能：神秘箱子前台控制器
 *
 * 提供神秘箱子相关接口：
 * - /mystery-box/status  查询当前可领取的箱子（给前端轮询）
 * - /mystery-box/claim   用户发送暗号领取箱子
 *
 * 领取流程：
 * 1. 用户在聊天框发送暗号（前端拦截后调用此接口）
 * 2. 验证暗号匹配、箱子未过期、未已领取
 * 3. 随机奖励金额（trap=扣，其余=加）
 * 4. 写货币流水日志
 * 5. 公屏广播结果（中奖/踩雷）
 *
 * @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\MysteryBox;
use App\Models\MysteryBoxClaim;
use App\Services\ChatStateService;
use App\Services\UserCurrencyService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

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

    /**
     * 查询当前可领取的箱子状态（给前端轮询/显示用）。
     */
    public function status(): JsonResponse
    {
        if (! GameConfig::isEnabled('mystery_box')) {
            return response()->json(['active' => false]);
        }

        $box = MysteryBox::currentOpenBox();

        if (! $box) {
            return response()->json(['active' => false]);
        }

        // 计算剩余时间
        $secondsLeft = $box->expires_at ? max(0, now()->diffInSeconds($box->expires_at, false)) : null;

        return response()->json([
            'active' => true,
            'box_id' => $box->id,
            'box_type' => $box->box_type,
            'type_name' => $box->typeName(),
            'type_emoji' => $box->typeEmoji(),
            'passcode' => $box->passcode,
            'seconds_left' => $secondsLeft,
        ]);
    }

    /**
     * 用户用暗号领取箱子。
     */
    public function claim(Request $request): JsonResponse
    {
        if (! GameConfig::isEnabled('mystery_box')) {
            return response()->json(['ok' => false, 'message' => '神秘箱子功能未开放。']);
        }

        $passcode = strtoupper(trim((string) $request->input('passcode', '')));

        if ($passcode === '') {
            return response()->json(['ok' => false, 'message' => '请输入暗号。']);
        }

        $user = $request->user();

        return DB::transaction(function () use ($user, $passcode): JsonResponse {
            // 查找匹配暗号的可领取箱子（加锁防并发）
            $box = MysteryBox::query()
                ->where('passcode', $passcode)
                ->where('status', 'open')
                ->where(fn ($q) => $q->whereNull('expires_at')->orWhere('expires_at', '>', now()))
                ->lockForUpdate()
                ->first();

            if (! $box) {
                return response()->json(['ok' => false, 'message' => '暗号不正确，或箱子已被领走/已过期。']);
            }

            // ① 随机奖励金额
            $reward = $box->rollReward();

            // ② 货币变更
            $source = $reward >= 0 ? CurrencySource::MYSTERY_BOX : CurrencySource::MYSTERY_BOX_TRAP;
            $remark = $reward >= 0
                ? "神秘箱子【{$box->typeName()}】奖励"
                : '神秘箱子【黑化箱】陷阱扣除';

            $this->currency->change($user, 'gold', $reward, $source, $remark, $box->room_id);

            // ③ 写领取记录 + 更新箱子状态
            MysteryBoxClaim::create([
                'mystery_box_id' => $box->id,
                'user_id' => $user->id,
                'reward_amount' => $reward,
            ]);

            $box->update(['status' => 'claimed']);

            // ④ 公屏广播结果
            $user->refresh();
            $this->broadcastResult($box, $user->username, $reward);

            return response()->json([
                'ok' => true,
                'reward' => $reward,
                'balance' => $user->jjb ?? 0,
                'message' => $reward >= 0
                    ? "🎉 恭喜！开箱获得 +{$reward} 金币！"
                    : '☠️ 中了黑化陷阱！扣除 '.abs($reward).' 金币！',
            ]);
        });
    }

    /**
     * 公屏广播开箱结果。
     *
     * @param  MysteryBox  $box  箱子实例
     * @param  string  $username  领取者用户名
     * @param  int  $reward  奖励金额（正/负）
     */
    private function broadcastResult(MysteryBox $box, string $username, int $reward): void
    {
        $emoji = $box->typeEmoji();
        $typeName = $box->typeName();

        if ($reward >= 0) {
            $content = "{$emoji}【神秘箱子】开箱播报：恭喜 【{$username}】 抢到了神秘{$typeName}！"
                .'获得 💰'.number_format($reward).' 金币！';
            $color = $box->box_type === 'rare' ? '#c4b5fd' : '#34d399';
        } else {
            $content = "☠️【神秘箱子】《黑化陷阱》haha！【{$username}】 中了神秘黑化箱的陷阱！"
                .'被扣除 💰'.number_format(abs($reward)).' 金币！点背~';
            $color = '#f87171';
        }

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

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