<?php
// 抽奖核心服务
namespace app\service;

use addons\webman\model\DrawRecord;
use addons\webman\model\Game;
use addons\webman\model\Prize;
use Exception;
use support\Db;
use support\Log;

class DrawService
{
    /**
     * 执行抽奖
     * @param  $player
     * @param int $gameId
     * @param int $departmentId
     * @param string $ip 用户IP
     * @return array 抽奖结果
     */
    public function execute( $player, int $gameId, int $departmentId, string $ip): array
    {
        try {
            DB::beginTransaction();

            // 1. 查询有效奖品（加行锁防止并发问题）
            $prizes = Prize::query()->where('game_id', $gameId)
                ->where('department_id', $departmentId)
                ->where('status', 1)
                ->where('total_remaining', '>', 0)
                ->where('daily_remaining', '>', 0)
                ->lockForUpdate()
                ->get()
                ->toArray();

            if (empty($prizes)) {
                DB::rollBack();
                return [
                    'success' => false,
                    'message' => '当前游戏不可用'
                ];
            }

            $game = Game::query()->select('id', 'game_type', 'consume')->where('id', $gameId)->first()->toArray();
            // 2. 计算中奖结果
            $result = $this->calculateWinning($player,$prizes, $game['consume']);
            $prizeId = $result['prize_id'];
            $prizeName = $result['prize_name'];
            $prizeType = $result['prize_type'];

            $game['department_id'] = $departmentId;
            // 3. 记录抽奖信息
            $this->createRecord($player->id, $result, $game, $ip);

            if ($result['prize_type'] == 3) {
                $message = '很遗憾，未中奖';
            } else {
                $message = '恭喜获得' . $prizeName;
            }
            DB::commit();
            return [
                'prize_id' => $prizeId,
                'prize_name' => $prizeName,
                'prize_type' => $prizeType,
                'consume' => $game['consume'],
                'message' => $message
            ];
        } catch (Exception $e) {
            DB::rollBack();
            Log::error("抽奖失败：{$e->getMessage()}", [
                'user_id' => $player->id,
                'trace' => $e->getTraceAsString()
            ]);
            return [
                'success' => false,
                'message' => '抽奖过程异常，请稍后再试'
            ];
        }
    }

    /**
     * 计算中奖结果
     * @param array $prizes 有效奖品列表
     * @return array 中奖信息
     * @throws Exception
     */
    private function calculateWinning($player, array $prizes, $consume): array
    {
        // 计算总概率权重
        $totalProb = array_sum(array_column($prizes, 'probability'));
        if ($totalProb <= 0) {
            return ['prize_id' => null, 'type' => Prize::PRIZE_TYPE_LOSE, 'prize_name' => '未中奖', 'prize_pic' => null];
        }
        $player->wallet->decrement('money', $consume);
        // 生成随机数（0到总权重之间）
        $random = mt_rand(1, $totalProb * 10000) / 10000; // 提高精度

        $currentSum = 0;
        foreach ($prizes as $prize) {
            $currentSum += $prize['probability'];
            if ($random <= $currentSum) {
                // 检查并扣减库存
                $this->deductStock($prize['id']);
                return [
                    'prize_id' => $prize['id'],
                    'prize_type' => $prize['type'],
                    'prize_name' => $prize['name'],
                    'prize_pic' => $prize['pic']
                ];
            }
        }

        return ['prize_id' => null, 'type' => Prize::PRIZE_TYPE_LOSE,  'prize_name' => '未中奖', 'prize_pic' => null];
    }

    /**
     * 扣减库存
     * @param int $prizeId 奖品ID
     * @throws Exception
     */
    private function deductStock(int $prizeId): void
    {
        $prize = Prize::query()->findOrFail($prizeId);

        // 再次检查库存（防止并发超卖）
        if ($prize->total_remaining <= 0 || $prize->daily_remaining <= 0) {
            throw new \Exception("奖品库存不足");
        }

        $prize->decrement('total_remaining');
        $prize->decrement('daily_remaining');
        $prize->save();
    }

    /**
     * 创建抽奖记录
     * @param int $userId 用户ID
     * @param array|null $prize 奖品
     * @param string $ip IP地址
     */
    private function createRecord(int $userId, ?array $prize, array $game, string $ip): void
    {
        DrawRecord::query()->create([
            'uid' => $userId,
            'prize_id' => $prize['prize_id'],
            'prize_type' => $prize['prize_type'],
            'prize_name' => $prize['prize_name'],
            'prize_pic' => $prize['prize_pic'],
            'game_id' => $game['id'],
            'consume' => $game['consume'],
            'game_type' => $game['game_type'],
            'department_id' => $game['department_id'],
            'draw_time' => date('Y-m-d H:i:s'),
            'ip' => $ip
        ]);
    }
}