<?php
// +----------------------------------------------------------------------
// | saiadmin [ saiadmin快速开发框架 ]
// +----------------------------------------------------------------------
// | Author: your name
// +----------------------------------------------------------------------
namespace app\dice\logic\lottery_pool_config;

use app\api\cache\UserCache;
use app\api\service\LotteryService;
use app\dice\helper\AdminScopeHelper;
use app\dice\helper\ConfigScopeEditHelper;
use app\dice\model\lottery_pool_config\DiceLotteryPoolConfig;
use app\dice\model\player\DicePlayer;
use app\dice\basic\DiceBaseLogic;
use plugin\saiadmin\exception\ApiException;
use plugin\saiadmin\utils\Helper;
use support\think\Cache;
use support\think\Db;

/**
 * 色子奖池配置逻辑层
 */
class DiceLotteryPoolConfigLogic extends DiceBaseLogic
{
    /** Redis 当前彩金池（type=0 实例）key，无则按 type=0 创建 */
    private const REDIS_KEY_CURRENT_POOL = 'api:game:lottery_pool:default';

    private const EXPIRE = 86400 * 7;

    /**
     * 构造函数
     */
    public function __construct()
    {
        $this->model = new DiceLotteryPoolConfig();
    }

    /**
     * 按渠道隔离更新（主键 id 全局唯一，仍校验 dept_id 防止越权）
     */
    public function edit($id, array $data, ?array $adminInfo = null, $requestDeptId = null): mixed
    {
        $pickedDeptId = AdminScopeHelper::pickRequestDeptId($requestDeptId, $data);
        $deptId = AdminScopeHelper::resolveConfigDeptId($adminInfo, $pickedDeptId);
        $result = ConfigScopeEditHelper::updateByPkAndDept(
            $this->model,
            $id,
            $deptId,
            $data,
            ['id', 'dept_id', 'create_time', 'update_time', 'delete_time', 'row_id'],
            $adminInfo,
            $pickedDeptId
        );
        if ($result) {
            $pool = DiceLotteryPoolConfig::where('id', $id)->find();
            if ($pool && $pool->isPlayerDefaultTemplate()) {
                $this->syncPlayersBoundToPlayerDefaultPool($pool);
            }
        }
        return $result;
    }

    /**
     * 修改 playerDefault 后：同步同渠道所有绑定该池（及应跟随 playerDefault 的玩家）T1–T5 权重，并刷新 Redis
     *
     * @return int 已同步玩家数量
     */
    public function syncPlayersBoundToPlayerDefaultPool(DiceLotteryPoolConfig $pool): int
    {
        $poolId = (int) ($pool->id ?? 0);
        if ($poolId <= 0) {
            return 0;
        }
        $fresh = DiceLotteryPoolConfig::where('id', $poolId)->find();
        if (!$fresh || !$fresh->isPlayerDefaultTemplate()) {
            return 0;
        }
        $pool = $fresh;

        $weights = $this->extractPoolTierWeights($pool);
        $poolDeptId = AdminScopeHelper::normalizeRecordDeptId($pool->dept_id ?? null);
        $legacyDefaultPoolId = $this->findDefaultPoolIdForDept($poolDeptId);

        $idsMap = [];

        $boundPlayers = DicePlayer::where('lottery_config_id', $poolId)->select();
        foreach ($boundPlayers as $player) {
            $idsMap[(int) $player->id] = true;
        }

        if ($legacyDefaultPoolId > 0 && $legacyDefaultPoolId !== $poolId) {
            $legacyPlayers = DicePlayer::where('lottery_config_id', $legacyDefaultPoolId)->select();
            foreach ($legacyPlayers as $player) {
                if (AdminScopeHelper::resolvePlayerConfigDeptId($player) === $poolDeptId) {
                    $idsMap[(int) $player->id] = true;
                }
            }
        }

        $unboundPlayers = DicePlayer::where(function ($q) {
            $q->where('lottery_config_id', 0)->whereOr('lottery_config_id', null);
        })->select();
        foreach ($unboundPlayers as $player) {
            if (AdminScopeHelper::resolvePlayerConfigDeptId($player) === $poolDeptId) {
                $idsMap[(int) $player->id] = true;
            }
        }

        if ($idsMap === []) {
            return 0;
        }

        $ids = array_keys($idsMap);
        $update = array_merge($weights, ['lottery_config_id' => $poolId]);
        Db::table('dice_player')->whereIn('id', $ids)->update($update);

        foreach ($ids as $playerId) {
            LotteryService::patchPlayerWeightsCache($playerId, $weights);
            LotteryService::invalidatePlayerLotteryCache($playerId);
            UserCache::deleteUser($playerId);
        }

        return count($ids);
    }

    /**
     * @return array{t1_weight:float,t2_weight:float,t3_weight:float,t4_weight:float,t5_weight:float}
     */
    private function extractPoolTierWeights(DiceLotteryPoolConfig $pool): array
    {
        $data = $pool->getData();
        return [
            't1_weight' => (float) ($data['t1_weight'] ?? 0),
            't2_weight' => (float) ($data['t2_weight'] ?? 0),
            't3_weight' => (float) ($data['t3_weight'] ?? 0),
            't4_weight' => (float) ($data['t4_weight'] ?? 0),
            't5_weight' => (float) ($data['t5_weight'] ?? 0),
        ];
    }

    private function findDefaultPoolIdForDept(int $deptId): int
    {
        $query = DiceLotteryPoolConfig::where('name', 'default');
        if (AdminScopeHelper::isTemplateDeptId($deptId)) {
            $query->where(function ($q) {
                $q->where('dept_id', AdminScopeHelper::DEFAULT_TEMPLATE_DEPT)
                    ->whereOr('dept_id', null);
            });
        } else {
            $query->where('dept_id', $deptId);
        }
        $row = $query->find();
        return $row ? (int) $row->id : 0;
    }

    /**
     * 获取当前彩金池（type=0）+ 杀分权重为 type=1 的只读展示
     * profit_amount 每次从 DB 实时读取；t1_weight～t5_weight 来自 type=1（杀分权重，不可在弹窗内修改）
     *
     * @return array{id:int,name:string,safety_line:int,kill_enabled:int,t1_weight:int,...,t5_weight:int,profit_amount:float}
     */
    public function getCurrentPool(int $deptId = AdminScopeHelper::DEFAULT_TEMPLATE_DEPT): array
    {
        $query0 = DiceLotteryPoolConfig::where('name', 'default');
        if (AdminScopeHelper::isTemplateDeptId($deptId)) {
            $query0->where(function ($q) {
                $q->where('dept_id', AdminScopeHelper::DEFAULT_TEMPLATE_DEPT)
                    ->whereOr('dept_id', null);
            });
        } else {
            $query0->where('dept_id', $deptId);
        }
        $configType0 = $query0->find();
        if (!$configType0) {
            throw new ApiException('No name=default pool config found, please create one first');
        }
        $query1 = DiceLotteryPoolConfig::where('name', 'killScore');
        if (AdminScopeHelper::isTemplateDeptId($deptId)) {
            $query1->where(function ($q) {
                $q->where('dept_id', AdminScopeHelper::DEFAULT_TEMPLATE_DEPT)
                    ->whereOr('dept_id', null);
            });
        } else {
            $query1->where('dept_id', $deptId);
        }
        $configType1 = $query1->find();
        $row0 = $configType0->toArray();
        $profitAmount = isset($row0['profit_amount']) ? (float) $row0['profit_amount'] : (isset($row0['ev']) ? (float) $row0['ev'] : 0.0);
        $pool = [
            'id'            => (int) $row0['id'],
            'name'          => (string) ($row0['name'] ?? ''),
            'safety_line'   => (int) ($row0['safety_line'] ?? 0),
            'kill_enabled'  => (int) ($row0['kill_enabled'] ?? 1),
            'profit_amount' => $profitAmount,
        ];
        $row1 = $configType1 ? $configType1->toArray() : [];
        $pool['t1_weight'] = (int) ($row1['t1_weight'] ?? 0);
        $pool['t2_weight'] = (int) ($row1['t2_weight'] ?? 0);
        $pool['t3_weight'] = (int) ($row1['t3_weight'] ?? 0);
        $pool['t4_weight'] = (int) ($row1['t4_weight'] ?? 0);
        $pool['t5_weight'] = (int) ($row1['t5_weight'] ?? 0);
        return $pool;
    }

    /**
     * 更新当前彩金池：仅允许修改 type=0 的 safety_line、kill_enabled（杀分权重来自 type=1，不可在此接口修改）
     *
     * @param array{safety_line?:int,kill_enabled?:int} $data
     */
    public function updateCurrentPool(array $data, int $deptId = AdminScopeHelper::DEFAULT_TEMPLATE_DEPT): void
    {
        $pool = $this->getCurrentPool($deptId);
        $id = (int) $pool['id'];
        if (!array_key_exists('safety_line', $data) && !array_key_exists('kill_enabled', $data)) {
            return;
        }
        $update = [];
        if (array_key_exists('safety_line', $data)) {
            $update['safety_line'] = (int) $data['safety_line'];
        }
        if (array_key_exists('kill_enabled', $data)) {
            $update['kill_enabled'] = ((int) $data['kill_enabled']) === 1 ? 1 : 0;
        }
        if ($update === []) {
            return;
        }
        $query = DiceLotteryPoolConfig::where('id', $id);
        ConfigScopeEditHelper::applyDeptIdWhere($query, $deptId);
        $query->update($update);
    }

    /**
     * 重置当前彩金池的玩家累计盈利：将 profit_amount 置为 0，并刷新 Redis 缓存
     */
    public function resetProfitAmount(int $deptId = AdminScopeHelper::DEFAULT_TEMPLATE_DEPT): void
    {
        $pool = $this->getCurrentPool($deptId);
        $id = (int) $pool['id'];
        $query = DiceLotteryPoolConfig::where('id', $id);
        ConfigScopeEditHelper::applyDeptIdWhere($query, $deptId);
        $query->update(['profit_amount' => 0]);
        $pool['profit_amount'] = 0.0;
        Cache::set(self::REDIS_KEY_CURRENT_POOL, json_encode($pool), self::EXPIRE);
    }
}
