<?php

require_once __DIR__ . '/Activity/ActInterface.php';
$actModelDir = __DIR__ . '/Activity';
$dh = opendir($actModelDir);
while ($file = readdir($dh)) {
    if (in_array($file, ['.', '..'])) continue;
    require_once __DIR__ . '/Activity/' . $file;
}

class ActBaseModel
{
    const ACT_LIST = [
        SURPRISE_CARD,
        MAYA_WHEEL,
        TAROT,
        TAROT2,
        CLUB_FARM,
        TRAFFIC_PERMIT,
        LUCKY_DICE,
        COIN_PUSH_MANIA,
        SURPRISE_COLLECT,
        SURPRISE_COLLECT_ATTACK,
        JACKPOT,
        KING_OF_CARDS,
        ONE_PLUS_GIFT,
        ONE_PLUS_TWO,
        ONE_PLUS_THREE,
        ONE_PLUS_SIX,
        SERIAL_MISSIONS,
        DREAM_MISSIONS,
        LUCKY_SCRATCH,
        SUPER_GASHAPON,
        LUCKY_FOX,
        AD_MISSIONS,
        RUNNING_RABBIT,
        TASK_EXPRESS,
        STARLIGHT_TREASURE,
        MULTIROUND_TIME_LIMITED_CARD,
        CRAZY_TOKEN,
        TREASURE,
        LUCKY_JOURNEY,
        TOKEN_RANK,
    ];
    static $actGTypeMap = [];
    static $actGroupMapping = [];
    static $taskMapping = [
        1 => '累计登陆天数',// Task_sumLogin
        2 => '建造次数',// Task_build
        3 => '偷次数',// Task_steal
        4 => '打次数',// Task_attack
        5 => '用宠物偷次数',// Task_useStealPet
        6 => '用宠物打次数',// Task_useAttackPet
        7 => '喂食宠物次数',// Task_feedPet
        8 => '喂食偷宠物次数',// Task_feedStealPet
        9 => '喂食打宠物次数',// Task_feedAttackPet
        10 => '喂食盾宠物次数',// Task_feedShieldPet
        11 => '升级宠物次数',// Task_upPetLevel
        12 => '升级偷宠物次数',// Task_upStealPetLevel
        13 => '升级打宠物次数',// Task_upAttackPetLevel
        14 => '升级盾宠物次数',// Task_upShieldPetLevel
        15 => '获取卡片次数',// Task_getCard
        16 => '获取新的星光卡次数',// Task_getBlackGoldCard
        17 => '使用小丑卡次数',// Task_useJokerCard
        18 => '支付次数',// Task_pay
        19 => '开启付费通行证',// Task_openPassGame
        20 => '购买偷惊喜礼包',// Task_buyStealSurpriseGift
        21 => '购买打惊喜礼包',// Task_buyAttackSurpriseGift
        22 => '锦标赛排名第1名',// Task_rankingLimit_1
        23 => '锦标赛排名前3',// Task_rankingLimit_3
        24 => '锦标赛排名前10',// Task_rankingLimit_10
        25 => '完成体力大师层数',// Task_passSpinMaster
        26 => '完成拼图张数',// Task_finishJigsaw
        27 => '打开限时宝箱个数',// Task_openTimeLimitedChest
        28 => '通关金币老虎机次数',// Task_PassTreasureTimes
        29 => '收集星光卡张数',//Task_getBlackGoldCard
        30 => '收集金卡张数',//Task_getGoldCard
        31 => '锦标赛排名前5',//Task_rankingLimit_5
        32 => '分享游戏次数',//Task_share
        33 => '锦标赛排名前20',//Task_rankingLimit_20
//        34 => '使用皮纳塔代币',//Task_usePinataToken
        35 => '使用玛雅代币',//Task_useMayaToken
        36 => '使用扭蛋代币',//Task_useSuperEggToken
        37 => '使用幸运小丑代币',//Task_useLuckyFoxToken 别名幸运狐狸
//        38 => '使用幸运旅途代币',//Task_useLuckyJourney
//        39 => '使用限时岛屿建造代币',//Task_useLTBuildToken
//        40 => '使用神秘宝矿代币',//Task_useMysteryMineToken
//        41 => '使用惊喜骰子代币',//Task_useSurpriseDice
//        42 => '使用隐秘宝藏代币',//Task_useHiddenTreasureToken
        43 => '使用塔罗牌代币',//Task_useTarotToken
        44 => '使用推币机代币',//Task_useCoinPushToken
        45 => '使用暴走兔子代币',//Task_useRunningRabbitToken
        46 => '获得拼图碎片',//Task_GetJigsawToken
        47 => '使用星图代币',//Task_useStarLightToken
    ];
    static $multiNumTypeReward = [
        '随机金卡',
        '随机星光卡',
        '随机限时金卡',
        '随机限时星光卡',
        '金币'
    ];
    static $rewardNames = [
        "木质宝箱" => 1,
        "白银宝箱" => 2,
        "黄金宝箱" => 3,
        "魔幻宝箱" => 4,
        "宠物经验" => 8,
        "宠物食物" => 9,
        "随机金卡" => 13,
        "金币" => 14,
        "体力" => 15,
        "小丑卡" => 18,
        "通行证经验" => 38,
        "拼图碎片" => 44,
        "玛雅转盘代币" => 45,

        "随机星光卡" => 50,
        "随机限时金卡" => 49,
        "随机限时星光卡" => 50,
        "幸运小丑代币" => 51,
        "幸运狐狸代币" => 51,
        "超级扭蛋代币" => 60,
        "随机工会表情" => 61,
        "随机公会表情" => 61,
        "皮纳塔代币" => 62,
        "幸运旅途代币" => 65,
        "塔罗牌代币" => 70,
        "推币机代币"  =>72,
        "暴走兔子代币" => 74,
        "星图代币" => 77,
        "西部矿洞代币" => 79,

    ];
    static $needSkinRewards = [
        "皮肤宝箱" => 19,
        "头像框" => 23,
        "建筑大师活动" => 25,
        "气球活动" => 26,
        "体力加速活动" => 27,
        "金币大爆炸活动" => 28,
        "疯狂加倍" => 31,
        "建筑打折" => 32,
        "卡片爆炸" => 33,
        "商场优惠" => 34,
        "超级收集活动" => 35,
        "超级气球活动" => 36,
        "首冲优惠" => 37,
        "通行证倍率活动" => 39,
        "收集翻倍活动" => 40,
        "四选一活动" => 41,
        "金币老虎机活动" => 43,
        "疯狂的卡组" => 46,


        "疯狂建造活动" => 52,
        "超级攻击活动" => 53,
        "回归签到" => 54,
        "完美偷袭活动" => 55,
        "小丑卡保底值" => 56,
        "完美打活动" => 57,
        "皮肤宝箱最大体力" => 58,
        "richking最大金币" => 59,
        "四选一活动-农场大冒险" => 63,
        "限次数建造打折" => 64,
        "幸运骰子活动券" => 71,
        "Jackpot老虎机活动券"  =>73,
        "每日成就任务道具券" => 75,
        "付费成就活动道具券" => 76,
        "推币机道具券" => 78,
    ];

    static $actModels = [];

    protected $goodSku;
    protected $actType;

    function __construct($actType = '')
    {
        $this->goodSku = oo::cfg('sku');
        $this->actType = $actType;
    }

    static function getActModel(string $actType): ActInterface
    {
        if (isset(self::$actModels[$actType]) && self::$actModels[$actType] instanceof ActInterface) return self::$actModels[$actType];
        switch ($actType) {
            case SURPRISE_CARD:
                self::$actModels[$actType] = new SurpriseCardActModel($actType);
                break;
            case MAYA_WHEEL:
                self::$actModels[$actType] = new MayaActModel($actType);
                break;
            case TAROT:
            case TAROT2:
                self::$actModels[$actType] = new TarotActModel($actType);
                break;
            case CLUB_FARM:
                self::$actModels[$actType] = new ClubFarmActModel($actType);
                break;
            case TRAFFIC_PERMIT:
                self::$actModels[$actType] = new TrafficPermitActModel($actType);
                break;
            case LUCKY_DICE:
                self::$actModels[$actType] = new LuckDiceActModel($actType);
                break;
            case LUCKY_FOX:
                self::$actModels[$actType] = new LuckFoxActModel($actType);
                break;
            case COIN_PUSH_MANIA:
                self::$actModels[$actType] = new CoinPushManiaActModel($actType);
                break;
            case SURPRISE_COLLECT:
                self::$actModels[$actType] = new SurpriseCollectModel($actType);
                break;
            case SURPRISE_COLLECT_ATTACK:
                self::$actModels[$actType] = new SurpriseCollectAttackActModel($actType);
                break;
            case JACKPOT:
                self::$actModels[$actType] = new JackpotActModel($actType);
                break;
            case KING_OF_CARDS:
                self::$actModels[$actType] = new KingOfCardActModel($actType);
                break;
            case ONE_PLUS_GIFT:
            case ONE_PLUS_TWO:
            case ONE_PLUS_THREE:
            case ONE_PLUS_SIX:
                self::$actModels[$actType] = new OnePlusActModel($actType);
                break;
            case SERIAL_MISSIONS:
                self::$actModels[$actType] = new SerialMissionsActModel($actType);
                break;
            case DREAM_MISSIONS:
                self::$actModels[$actType] = new DreamMissionsActModel($actType);
                break;
            case LUCKY_SCRATCH:
                self::$actModels[$actType] = new LuckyScratchActModel($actType);
                break;
            case SUPER_GASHAPON:
                self::$actModels[$actType] = new SuperGashaponActModel($actType);
                break;
            case AD_MISSIONS:
                self::$actModels[$actType] = new AdMissionsActModel($actType);
                break;
            case RUNNING_RABBIT:
                self::$actModels[$actType] = new RunningRabbitActModel($actType);
                break;
            case TASK_EXPRESS:
                self::$actModels[$actType] = new TaskExpressActModel($actType);
                break;
            case STARLIGHT_TREASURE:
                self::$actModels[$actType] = new StartlightTreasureActModel($actType);
                break;
            case MULTIROUND_TIME_LIMITED_CARD:
                self::$actModels[$actType] = new MultiRoundTimeLimitedCardsModel($actType);
                break;
            case CRAZY_TOKEN:
                self::$actModels[$actType] = new CrazyTokenModel($actType);
                break;
            case TREASURE:
                self::$actModels[$actType] = new TreasureActModel($actType);
                break;
            case LUCKY_JOURNEY:
                self::$actModels[$actType] = new LuckyJourneyModel($actType);
                break;
            case TOKEN_RANK:
                self::$actModels[$actType] = new TokenRankModel($actType);
                break;
            default:
                self::response(__LINE__, "活动类型model不存在：" . $actType);
        }
        return self::$actModels[$actType];
    }

    static function response($ret = 0, $msg = '', array $data = array(), $type = false): string
    {
        header('Content-type:text/json');
        $result = [
            'ret' => $ret,
            'msg' => $msg,
            'data' => $data,
            'state' => $ret ? "error" : 'success'
        ];
        if ($type) {
            die(json_encode($result));
        } else {
            die(json_encode($result, JSON_NUMERIC_CHECK));
        }
        return '';
    }

    // redis最少一分钟, 最大7天
    static function getActCacheExpireTime($endTime){
        $time = time();
        return min(max($endTime, $time + 60), $time + 86400 * 7 );
    }
    // 解析三层映射关系 等级 => 体力 => 数数分组 3层嵌套
    public function parseLvSpinsShushuStagesMapping(array $stagesMappingArray): array
    {
        $rewardsConfig = $idxMapping = [];

        foreach ($stagesMappingArray as $k => $item) {
            if (empty($k)) continue;
            list($idx, $lvMin, $lvMax, $spinsMin, $spinsMax, $ssGroup) = $item;
            $lvKey = "{$lvMin}-$lvMax";
            $spinsKey = "{$spinsMin}-{$spinsMax}";

            $lvIdx = $this->getGroupMappingIdx(CONDITION_TYPE_LV, $lvKey);
            $spinsIdx = $this->getGroupMappingIdx(CONDITION_TYPE_SPINS, $spinsKey, $lvIdx);
            $ssIdx = $this->getGroupMappingIdx(CONDITION_TYPE_SHUSHU, $ssGroup, "{$spinsIdx}_{$lvIdx}");

            if (empty($rewardsConfig[$lvIdx]))
                $rewardsConfig[$lvIdx] = [
                    'stages' => [],
                    'lvStart' => $lvMin,
                    'lvEnd' => $lvMax,
                    'start' => $lvMin,
                    'end' => $lvMax,
                ];
            if (empty($rewardsConfig[$lvIdx]['stages'][$spinsIdx]))
                $rewardsConfig[$lvIdx]['stages'][$spinsIdx] = [
                    'stages' => [],
                    'spinsStart' => $spinsMin,
                    'spinsEnd' => $spinsMax,
                    'start' => $spinsMin,
                    'end' => $spinsMax,
                ];

            $shushus = $this->parseShushuGroups($ssGroup);
            if (empty($rewardsConfig[$lvIdx]['stages'][$spinsIdx]['stages'][$ssIdx]))
                $rewardsConfig[$lvIdx]['stages'][$spinsIdx]['stages'][$ssIdx] = [
                    'stages' => [],
                    'shushu' => $shushus,
                ];


            $idxMapping[$idx] = [$lvIdx, $spinsIdx, $ssIdx];
        }


        return [$rewardsConfig, $idxMapping];
    }


    // 解析三层映射关系V1 等级,体力,数数分组 同级
    public function parseLvSpinsShushuStagesMappingV1(array $stagesMappingArray): array
    {
        $rewardsConfig = [];

        foreach ($stagesMappingArray as $k => $item) {
            if (empty($k)) continue;
            list($idx, $lvMin, $lvMax, $spinsMin, $spinsMax, $ssGroup) = $item;

            $shushus = $this->parseShushuGroups($ssGroup);

            $rewardsConfig[] = [
                'id' => $idx,
                'lv_start' => $lvMin,
                'lv_end' => $lvMax,
                'spins_start' => $spinsMin,
                'spins_end' => $spinsMax,
                'shushu' => $shushus,
            ];
        }


        return $rewardsConfig;
    }

    public function parseLvCoinYShushuStagesMapping(array $stagesMappingArray): array
    {
        $rewardsConfig = $idxMapping = [];

        foreach ($stagesMappingArray as $k => $item) {
            if (empty($k)) continue;
            list($idx, $lvMin, $lvMax, $coinsyMin, $coinsyMax, $ssGroup) = $item;
            $lvKey = "{$lvMin}-$lvMax";
            $coinsyKey = "{$coinsyMin}-{$coinsyMax}";

            $lvIdx = $this->getGroupMappingIdx(CONDITION_TYPE_LV, $lvKey);
            $coinsyIdx = $this->getGroupMappingIdx(CONDITION_TYPE_COIN_Y, $coinsyKey, $lvIdx);
            $ssIdx = $this->getGroupMappingIdx(CONDITION_TYPE_SHUSHU, $ssGroup, "{$coinsyIdx}_{$lvIdx}");

            if (empty($rewardsConfig[$lvIdx]))
                $rewardsConfig[$lvIdx] = [
                    'stages' => [],
                    'lvStart' => $lvMin,
                    'lvEnd' => $lvMax,
                    'start' => $lvMin,
                    'end' => $lvMax,
                ];
            if (empty($rewardsConfig[$lvIdx]['stages'][$coinsyIdx]))
                $rewardsConfig[$lvIdx]['stages'][$coinsyIdx] = [
                    'stages' => [],
                    'coinsyStart' => $coinsyMin,
                    'coinsyEnd' => $coinsyMax,
                    'start' => $coinsyMin,
                    'end' => $coinsyMax,
                ];

            $shushus = $this->parseShushuGroups($ssGroup);
            if (empty($rewardsConfig[$lvIdx]['stages'][$coinsyIdx]['stages'][$ssIdx]))
                $rewardsConfig[$lvIdx]['stages'][$coinsyIdx]['stages'][$ssIdx] = [
                    'stages' => [],
                    'shushu' => $shushus,
                ];


            $idxMapping[$idx] = [$lvIdx, $coinsyIdx, $ssIdx];
        }


        return [$rewardsConfig, $idxMapping];
    }

    // 解析两层映射关系 等级 => 体力 2层嵌套
    public function parseLvSpinsStagesMapping(array $stagesMappingArray): array
    {
        $rewardsConfig = $idxMapping = [];

        for ($i = 1; $i < count($stagesMappingArray); $i++) {
            $item = $stagesMappingArray[$i];
            if (empty(array_filter($item))) continue;

            list($idx, $lvMin, $lvMax, $spinsMin, $spinsMax) = $item;
            $lvKey = "{$lvMin}-$lvMax";
            $spinsKey = "{$spinsMin}-{$spinsMax}";
            $lvIdx = $this->getGroupMappingIdx(CONDITION_TYPE_LV, $lvKey);
            $spinsIdx = $this->getGroupMappingIdx(CONDITION_TYPE_SPINS, $spinsKey, $lvIdx);

            if (empty($rewardsConfig[$lvIdx]))
                $rewardsConfig[$lvIdx] = [
                    'stages' => [],
                    'lvStart' => $lvMin,
                    'lvEnd' => $lvMax,
                    'start' => $lvMin,
                    'end' => $lvMax,
                ];
            if (empty($rewardsConfig[$lvIdx]['stages'][$spinsIdx]))
                $rewardsConfig[$lvIdx]['stages'][$spinsIdx] = [
                    'stages' => [],
                    'spinsStart' => $spinsMin,
                    'spinsEnd' => $spinsMax,
                    'start' => $spinsMin,
                    'end' => $spinsMax,
                ];

            $idxMapping[$idx] = [$lvIdx, $spinsIdx];
        }

        return [$rewardsConfig, $idxMapping];
    }

    public function parseLvStagesMapping(array $stagesMappingArray): array
    {
        $rewardsConfig = $idxMapping = [];
        for ($i = 1; $i < count($stagesMappingArray); $i++) {
            $item = $stagesMappingArray[$i];
            if (empty(array_filter($item))) continue;

            list($idx, $lvMin, $lvMax) = $item;
            $lvKey = "{$lvMin}-$lvMax";
            $lvIdx = $this->getGroupMappingIdx(CONDITION_TYPE_LV, $lvKey);

            if (empty($rewardsConfig[$lvIdx]))
                $rewardsConfig[$lvIdx] = [
                    'stages' => [],
                    'lvStart' => $lvMin,
                    'lvEnd' => $lvMax,
                    'start' => $lvMin,
                    'end' => $lvMax,
                ];

            $idxMapping[$idx] = [$lvIdx];
        }

        return [$rewardsConfig, $idxMapping];
    }

    // 解析两层映射关系 等级 => 数数分组 2层嵌套
    public function parseLvShushuStagesMapping(array $stagesMappingArray): array
    {
        $rewardsConfig = $idxMapping = [];

        for ($i = 1; $i < count($stagesMappingArray); $i++) {
            $item = $stagesMappingArray[$i];
            if (empty(array_filter($item))) continue;

            list($idx, $lvMin, $lvMax, $shushuGroups) = $item;
            $lvKey = "{$lvMin}-$lvMax";
            $lvIdx = $this->getGroupMappingIdx(CONDITION_TYPE_LV, $lvKey);
            $ssIdx = $this->getGroupMappingIdx(CONDITION_TYPE_SHUSHU, $shushuGroups, $lvIdx);

            if (empty($rewardsConfig[$lvIdx]))
                $rewardsConfig[$lvIdx] = [
                    'stages' => [],
                    'lvStart' => $lvMin,
                    'lvEnd' => $lvMax,
                    'start' => $lvMin,
                    'end' => $lvMax,
                ];
            if (empty($rewardsConfig[$lvIdx]['stages'][$ssIdx]))
                $rewardsConfig[$lvIdx]['stages'][$ssIdx] = [
                    'stages' => [],
                    'shushu' => $this->parseShushuGroups($shushuGroups),
                ];

            $idxMapping[$idx] = [$lvIdx, $ssIdx];
        }

        return [$rewardsConfig, $idxMapping];
    }


    # 通过奖励名 解析奖励类型以及皮肤id
    public function parseRewardTypeAndSkinId($rewardName, $line = 0)
    {
        #常规奖励 无皮肤
        if (!empty(self::$rewardNames[$rewardName])) {
            return [self::$rewardNames[$rewardName], ''];
        }
        $prizeList = oo::commonOprModel('config')->getPropsConfigFromLocal();
        foreach ($prizeList as $item) {
            if (empty($item['skinList'])) continue;
            foreach ($item['skinList'] as $skinItem) {
                if ($skinItem['name'] == $rewardName && !empty(self::$needSkinRewards[$item['name']])) {
                    return [self::$needSkinRewards[$item['name']], $skinItem['id']];
                }
            }
        }
        #判断奖励是否存在
        self::response(-1, "第{$line}行,奖励或皮肤不存在:'{$rewardName}'", $prizeList);
    }

    # 通过分组名，解析分组id
    public function parseShushuGroups($shushuGroups, $line = 0)
    {
        if (empty($shushuGroups)) self::response(-1, $line . '行，数数分组为空');
        if (is_string($shushuGroups)) {
            $shushuGroups = strtr($shushuGroups, ['，' => ',']);
            $shushuGroups = explode(',', $shushuGroups);
        }
        $allGroups = array_column(oo::commonOprModel('config')->getUserGroupConfigByCid(5), 'name', 'id');
        $allGroups = oo::commonOprModel('config')->hideSSGroup($allGroups);;
        $shushuGroupIds = [];
        foreach ($shushuGroups as $shushuGroup) {
            if (!in_array($shushuGroup, $allGroups)) self::response(-1, "第{$line}行,数数分组不存在:'{$shushuGroup}'");
            $shushuGroupIds[] = array_search($shushuGroup, $allGroups);
        }
        return $shushuGroupIds;
    }

    # 通过虎机概率分组名，解析 老虎机概率分组id
    public function parseSlotWeightGroups(string $slotWeightGroupName, $line = 0): int
    {
        if (empty($slotWeightGroupName)) self::response(-1, $line . '行，老虎机概率分组为空');

        $groupsTbl = otable::slotWeightGroups();
        $groups = oo::commonOprDb('slavedb')->getOne("select * from {$groupsTbl} where `name`='{$slotWeightGroupName}'");
        if (empty($groups['id'])) self::response(-1, "第{$line}行,老虎机概率分组不存在:'{$slotWeightGroupName}'");
        return intval($groups['id']);
    }

    # 解析分层映射的每层idx
    public function getGroupMappingIdx($type, $val, $parentsKey = 0)
    {
        self::$actGroupMapping[$type] = self::$actGroupMapping[$type] ?? [];
        self::$actGroupMapping[$type][$parentsKey] = self::$actGroupMapping[$type][$parentsKey] ?? [];
        if (empty(self::$actGroupMapping[$type][$parentsKey][$val])) {
            self::$actGroupMapping[$type][$parentsKey][$val] = count(self::$actGroupMapping[$type][$parentsKey]) + 1;
        }
        return intval(self::$actGroupMapping[$type][$parentsKey][$val]);
    }

    # 解析一行奖励
    public function parseLineRewards(array $rewards, $line = 0)
    {
        $rewardsTemp = [];
        $i = 0;
        while ($i < count($rewards)) {
            $reward = $rewards[$i++];
            $isFixNum = $rewards[$i++];
            $rewardNum = intval($rewards[$i++]);
            if (!empty($reward)) {
                if (!in_array($reward, self::$multiNumTypeReward)) $isFixNum = '是';   #非金币奖励，全部固定值奖励
                $isFixNum = ($isFixNum == '是') ? 1 : 2;#固定值奖励 1 按等级取值 2
                list($type, $skin) = $this->parseRewardTypeAndSkinId($reward, $line);

                if (empty($rewardNum)) self::response(-1, "第{$line}行,奖励数为空", $rewards);
                $currentId = count($rewardsTemp) + 1;
                $rewardsTemp[] = [
                    'id' => $currentId,
                    "num" => $rewardNum,
                    "type" => $type,
                    "propsId" => $type,
                    "rtype" => $isFixNum,
                    "skin" => intval($skin)
                ];
            }
        }
        return $rewardsTemp;
    }

    # 解析是否 是 1 否 0
    public function parseYesOrNo($text)
    {
        return $text == '是' ? 1 : 0;
    }

    public function writeActCacheCommonLvSpinsShushu(array $actConfig, string $configColumn = 'reward_info'): bool
    {
        $conditionKeys = okeys::activityConditionKeys($actConfig['aid']);
        $stageRewardKeys = okeys::activityRewardsStageKeys($actConfig['aid']);
        $rewardInfo = json_decode($actConfig[$configColumn], true);
        foreach ($rewardInfo as $idx1 => $item1) {
            foreach ($item1['stages'] as $idx2 => $item2) {
                foreach ($item2['stages'] as $idx3 => $item3) {
                    $stageKey = "{$idx1}_{$idx2}_{$idx3}";
                    $stageConditions = $this->getStageConditionLvSpinsShushu($item1, $item2, $item3);
                    oo::commonOprRedis('games')->hset($conditionKeys, $stageKey, json_encode($stageConditions, JSON_NUMERIC_CHECK));
                    oo::commonOprRedis('games')->hset($stageRewardKeys, $stageKey, json_encode($item3, JSON_NUMERIC_CHECK));
                }
            }
        }

        $expireTime = max($actConfig['end_time'], time() + 60);#redis最少一分钟
        oo::commonOprRedis('games')->expireAt($conditionKeys, oo::redisRandomExpire($expireTime));
        oo::commonOprRedis('games')->expireAt($stageRewardKeys, oo::redisRandomExpire($expireTime));
        return true;
    }

    public function getStageConditionLvSpinsShushu(array $lvItem, $spinsItem, $shushuItem): array
    {
        return [
            [
                "start" => $lvItem['lv_start'] ?? $lvItem['lvStart'] ?? $lvItem['start'],
                "end" => $lvItem['lv_end'] ?? $lvItem['lvEnd'] ?? $lvItem['end'],
                "shushu" => [],
                "type" => CONDITION_TYPE_LV
            ],
            [
                "start" => $spinsItem['spins_start'] ??  $spinsItem['spinsStart'] ?? $spinsItem['start'],
                "end" => $spinsItem['spins_end'] ??  $spinsItem['spinsEnd'] ?? $spinsItem['end'],
                "shushu" => [],
                "type" => CONDITION_TYPE_SPINS
            ],
            [
                "start" => 0,
                "end" => 0,
                "shushu" => $shushuItem['shushu'],
                "type" => CONDITION_TYPE_SHUSHU
            ],

        ];
    }
    public function getStageConditionLvCoinYShushu(array $lvItem, $spinsItem, $shushuItem): array
    {
        return [
            [
                "start" => $lvItem['lv_start'] ?? $lvItem['lvStart'] ?? $lvItem['start'],
                "end" => $lvItem['lv_end'] ?? $lvItem['lvEnd'] ?? $lvItem['end'],
                "shushu" => [],
                "type" => CONDITION_TYPE_LV
            ],
            [
                "start" => $spinsItem['spins_start'] ??  $spinsItem['spinsStart'] ?? $spinsItem['start'],
                "end" => $spinsItem['spins_end'] ??  $spinsItem['spinsEnd'] ?? $spinsItem['end'],
                "shushu" => [],
                "type" => CONDITION_TYPE_COIN_Y
            ],
            [
                "start" => 0,
                "end" => 0,
                "shushu" => $shushuItem['shushu'],
                "type" => CONDITION_TYPE_SHUSHU
            ],

        ];
    }

    public function getStageConditionLvShushu(array $lvItem, $shushuItem): array
    {
        return [
            [
                "start" => $lvItem['lvStart'] ?? $lvItem['start'],
                "end" => $lvItem['lvEnd'] ?? $lvItem['end'],
                "shushu" => [],
                "type" => CONDITION_TYPE_LV
            ],
            [
                "start" => 0,
                "end" => 0,
                "shushu" => $shushuItem['shushu'],
                "type" => CONDITION_TYPE_SHUSHU
            ],

        ];
    }

    public function getStageConditionLvSpins(array $lvItem, $spinsItem): array
    {
        return [
            [
                "start" => $lvItem['lvStart'] ?? $lvItem['start'],
                "end" => $lvItem['lvEnd'] ?? $lvItem['end'],
                "shushu" => [],
                "type" => CONDITION_TYPE_LV
            ],
            [
                "start" => $spinsItem['spinsStart'] ?? $spinsItem['start'],
                "end" => $spinsItem['spinsEnd'] ?? $spinsItem['end'],
                "shushu" => [],
                "type" => CONDITION_TYPE_SPINS
            ]

        ];
    }

    //
    public function getSkuByPrice($price, $allowedFree = false): string
    {
        foreach ($this->goodSku as $skuPrice) {
            if ($skuPrice['price'] == $price) {
                return $skuPrice['sku'];
            }
        }
        if ($allowedFree) return '';
        return $this->response(__LINE__, '价格无对应sku，价格：' . $price);
    }

    public function saveTokenGoods(array &$actConfig, string $savedColumn)
    {
        foreach ($actConfig['tokenGoods'] as $k => $tokenGood) {
            $actConfig['tokenGoods'][$k] = $this->formatTokenGoods($actConfig['type'], $tokenGood);
        }
        $actConfig[$savedColumn] = $actConfig['tokenGoods'];
        unset($actConfig['tokenGoods']);
    }

    // 代币商品格式化
    public function formatTokenGoods(string $actType, array $tokenGoods): array
    {
        $gtype = self::getGtypeByActType($actType);
        if (empty($gtype))self::response(__LINE__, '不支持代币弹窗的活动：' . $actType);
        $gid = $gtype * 10000;
        switch ($actType) {
            case MAYA_WHEEL:
                $propId = 45;
                break;
            case LUCKY_FOX:
                $propId = 51;
                break;
            case SUPER_GASHAPON:
                $propId = 60;
                break;
            case PINATA:
                $propId = 62;
                break;
            case LUCKY_JOURNEY:
                $propId = 65;
                break;
            case TAROT:
                $propId = 70;
                break;
            case TAROT2:
                $propId = 79;
                break;
            case COIN_PUSH_MANIA:
                $propId = 72;
                break;
            case RUNNING_RABBIT:
                $propId = 74;
                break;
            default:
                self::response(__LINE__, '不支持代币弹窗的活动：' . $actType);
        }
        $goods = [
            'goods' => []
        ];
        foreach ($tokenGoods['goods'] as $tokenGood) {
            $tokenGood['exceed'] = intval($tokenGood['exceed']);
            if ($tokenGood['exceed'] < 1){
                self::response(__LINE__, '限购次数异常：' . $tokenGood['exceed']);
            }
            $goods['exceed'] = $tokenGood['exceed'];
            $tokenGood['discount'] = floatval($tokenGood['discount']);
            if(empty($tokenGood['discount']) || $tokenGood['discount'] > 1)
                self::response(__LINE__, '代币折扣异常：' . $tokenGood['discount']);
            $tokenGood['gid'] = $gid++;
            $tokenGood['gtype'] = $gtype;
            $tokenGood['prize'] = [
                [
                    "id" => "1",
                    "rtype" => "1",
                    "num" => $tokenGood['tokenNum'],
                    "type" => $propId,
                ]
            ];
            $goods['goods'][] = $tokenGood;
        }
        return $goods;
    }

    // 代币商品格式化
    public function formatTokenGoodsSheet(array &$actConfig, $noTokenConfigArray, $idxMapping)
    {
        $gtype = self::getGtypeByActType($this->actType);
        if (empty($gtype))self::response(__LINE__, '不支持代币弹窗的活动：' . $this->actType);
        $tokenGoods = [];
        foreach ($noTokenConfigArray as $k => $item) {
            if (empty($k)) continue;
            if (empty(array_filter($item))) continue;
            @list($idx, $stage, $price, $discount, $tokenNum, $exceed) = $item;
            $lineNum = $k+1;
            if (empty(intval($exceed)))self::response(__LINE__, "第{$lineNum}行，限购次数为空");
            if (empty($idxMapping[$idx])) self::response(__LINE__, '索引id不存在：' . $idx);
            $stageKey = $this->getStageKey($idxMapping[$idx]);
            $tokenGoods[$stageKey] = $tokenGoods[$stageKey] ?? [
                'exceed' => $exceed,
                'goods' => [],
            ];
            $sku = $this->getSkuByPrice($price);
            $goodsLen = count($tokenGoods[$stageKey]['goods']);
            $tokenGoods[$stageKey]['goods'][$goodsLen] = [
                'id' => $goodsLen + 1,
                'gid' => $gtype * 10000 + $goodsLen,
                'price' => $price,
                'sku' => $sku,
                'gtype' => $gtype,
                'discount' => $discount,
                'tokenNum' => $tokenNum,
                'exceed' => intval($exceed),
            ];
        }
        $actConfig['tokenGoods'] = $tokenGoods;
    }

    public function getStageKey(array $idxMapping): string
    {
        $stageKey = '';
        foreach ($idxMapping as $k) {
            if (strlen($stageKey) == 0) $stageKey .= $k;
            else $stageKey .= '_' . $k;
        }
        return $stageKey;
    }

    public static function parseExtraBasicConfig($fieldMapping, $sheetData): array
    {
        $baseConfig = [];
        foreach ($sheetData as $line) {
            $configField = $fieldMapping[$line[0]];
            if (!empty($configField)) {
                $baseConfig[$configField] = $line[1];
            }
        }
        return $baseConfig;
    }


    // 通过活动类型获取活动商品gtype
    public static function getGtypeByActType(string $actType):int{
        if (empty(self::$actGTypeMap[$actType])){
            $tb = otable::gTypeGoods();
            $ret = oo::commonOprDb('slavedb')->getOne("SELECT * FROM {$tb} Where en_name='".$actType."'");
            self::$actGTypeMap[$actType] = @intval($ret['g_type']);
        }
        if(empty(self::$actGTypeMap[$actType]))self::response(__LINE__, '查询gtype失败：' . $actType);
        return self::$actGTypeMap[$actType];
    }

    public function getActBasicConfig(): array
    {
        return [];
    }

    public function checkConflictActs($actType, $startTime, $endTime){
        return;
        $tb = otable::activityConf();
        $acts = oo::commonOprDb('slavedb')->getAll("SELECT * FROM {$tb} Where type='{$actType}' and `start_time`<{$endTime} and `end_time` > {$startTime}");
        if(!empty($acts)){
            $actType = self::$actTypeMapping[$actType] ?? $actType;
            $startTimeFormat =  date('Y-m-d H:i:s', $startTime);
            $endTimeFormat =  date('Y-m-d H:i:s', $endTime);
            $this->response(-1 * __LINE__, "时间段:{$startTimeFormat}~~{$endTimeFormat} 存在活动-{$actType}");
        }
    }


    public static function getMultiStageKey($idxes):int
    {
        $stage = 0;
        foreach ($idxes as $idx){
            $stage = $idx + $stage * 10000;
        }
        return $stage;
    }
}