<?php

namespace App\Http\Controllers;

use App\Enums\CurrencySource;
use App\Events\MessageSent;
use App\Models\User;
use App\Services\ChatStateService;
use App\Services\UserCurrencyService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Redis;

/**
 * 文件功能：用户赚取金币与经验（观看视频广告等任务）控制器
 *
 * @author   ChatRoom Laravel
 *
 * @version  1.0.0
 */
class EarnController extends Controller
{
    public function __construct(
        private readonly ChatStateService $chatState,
        private readonly UserCurrencyService $currencyService,
    ) {}

    /**
     * @var int 每日观看最大次数限制
     */
    private int $maxDailyLimit = 3;

    /**
     * @var int 每次领奖后至少需要的冷却时间（秒）
     */
    private int $cooldownSeconds = 5;

    /**
     * 申领看视频的奖励
     * 成功看完视频后前端发起此请求。
     * 为防止刷包，必须加上每日总次数及短时频率限制。
     */
    public function claimVideoReward(Request $request): JsonResponse
    {
        /** @var User $user */
        $user = Auth::user();

        $userId = $user->id;
        $dateKey = now()->format('Y-m-d');

        $dailyCountKey = "earn_video:count:{$userId}:{$dateKey}";
        $cooldownKey = "earn_video:cooldown:{$userId}";

        // 1. 检查冷却时间
        if (Redis::exists($cooldownKey)) {
            return response()->json([
                'success' => false,
                'message' => '操作过快，请稍后再试。',
            ]);
        }

        // 2. 检查每日最大次数
        $todayCount = (int) Redis::get($dailyCountKey);
        if ($todayCount >= $this->maxDailyLimit) {
            return response()->json([
                'success' => false,
                'message' => "今日视频收益次数已达上限（每天最多{$this->maxDailyLimit}次），请明天再来。",
            ]);
        }

        // 3. 增加今日次数计数
        $newCount = Redis::incr($dailyCountKey);
        if ($newCount === 1) {
            Redis::expire($dailyCountKey, 86400 * 2);
        }

        // 4. 配置：单次 5000 金币，500 经验
        $rewardCoins = 5000;
        $rewardExp = 500;
        $roomId = (int) $request->input('room_id', 0);

        // 参照钓鱼逻辑：通过 UserCurrencyService 写日志并变更金币/经验
        $this->currencyService->change(
            $user, 'gold', $rewardCoins, CurrencySource::VIDEO_REWARD,
            "看视频赚取金币（第{$newCount}次）", $roomId,
        );

        $this->currencyService->change(
            $user, 'exp', $rewardExp, CurrencySource::VIDEO_REWARD,
            "看视频赚取经验（第{$newCount}次）", $roomId,
        );

        // 刷新模型以获取 service 原子更新后的最新字段值
        $user->refresh();

        // 5. 设置冷却时间
        Redis::setex($cooldownKey, $this->cooldownSeconds, 1);

        // 6. 广播全服系统消息
        if ($roomId > 0) {
            $promoTag = ' <span onclick="window.dispatchEvent(new CustomEvent(\'open-earn-panel\'))" '
                .'style="display:inline-block;margin-left:6px;padding:1px 7px;background:#e9e4f5;'
                .'color:#6d4fa8;border-radius:10px;font-size:10px;cursor:pointer;font-weight:bold;vertical-align:middle;'
                .'border:1px solid #d0c4ec;" title="点击赚金币">💰 看视频赚金币</span>';

            $sysMsg = [
                'id' => $this->chatState->nextMessageId($roomId),
                'room_id' => $roomId,
                'from_user' => '系统播报',
                'to_user' => '大家',
                'content' => "👍 【{$user->username}】刚刚看视频赚取了 {$rewardCoins} 金币 + {$rewardExp} 经验！{$promoTag}",
                'is_secret' => false,
                'font_color' => '#16a34a',
                'action' => '',
                'sent_at' => now()->toDateTimeString(),
            ];

            $this->chatState->pushMessage($roomId, $sysMsg);
            broadcast(new MessageSent($roomId, $sysMsg));
        }

        $remainingToday = $this->maxDailyLimit - $newCount;

        return response()->json([
            'success' => true,
            'message' => "观看完毕！获得 {$rewardCoins} 金币 + {$rewardExp} 经验。今日还可观看 {$remainingToday} 次。",
            'new_jjb' => $user->jjb,
            'level_up' => false,
            'new_level_name' => '',
        ]);
    }
}
