<?php

class NewShopModel extends CI_Model
{
    const IMG_NAME_SPRINT_PAY = 'sprintPay';            //冲刺礼包
    const IMG_NAME_FIRST_PAY = 'firstPay';              //首充礼包
    const IMG_NAME_UNFITNESS_PAY = 'unfitnessPay';      //体力不足礼包
    const IMG_NAME_UPGRADE_PAY = 'upgradePay';          //升级礼包

    private $giftPackGoodsTable;
    private $gTypeGoodsTable;
    private $propsConfig;
    private $ssGroupList;
    private $gTypeMap;
    private $payFixFields;

    private $basicFieldsMap = [
        '唯一ID' => 'uuid',
        '等级下限' => 'min_level',
        '等级上限' => 'max_level',
        '购买价格' => 'price',
        '数数分组' => 'ss_group',
        '配图' => 'skin_dir',
    ];

    private $extraFieldsMap = [
        '唯一ID' => 'uuid',
        '优惠显示' => 'showMultiple',
    ];

    const MultiNumTypeReward = ['随机金卡', '金币'];

    public function __construct()
    {
        parent::__construct();
        $this->giftPackGoodsTable = otable::giftPackGoods();
        $this->gTypeGoodsTable = otable::gTypeGoods();
        $this->propsConfig = oo::commonOprModel('config')->getPropsConfigFromLocal('func');
        $this->ssGroupList = array_column(oo::commonOprModel('config')->getUserGroupConfigByCid(5), 'name', 'id');
        $this->gTypeMap = self::getGTypeMap();

        $this->load->library('PHPExcel');
        $this->load->library('PHPExcel/PHPExcel/IOFactory');
        $this->load->library('curl');
    }

    /**
     * 插入一条首充商品信息
     */
    public function insertFirstPayGoods(array $data, int $gType)
    {
        $formData = array(
            'gid' => 601,
            'g_type' => $gType,
            'desc' => '首充礼包商品',
            'sku' => $this->matchSKU($data['price']),
            'prize_json' => $this->formatPrize($data['props']['prizeJson'] ?? []),
            'other_json' => $this->formatPrize($data['other_json'] ?? []),
        );
        unset($data['props']);

        $this->insertGoods(array_merge($data, $formData));
    }

    /**
     * 更新首充商品信息
     */
    public function updateFirstPayGoods(array $data)
    {
        foreach ($data['good'] as $goodId => $oneGoods) {
            $oneGoods['sku'] = $this->matchSKU($oneGoods['price']);
            $oneGoods['prize_json'] = $this->formatPrize($data['props'][$goodId] ?? []);

            $this->updateGoods($oneGoods, "id=$goodId");
        }
    }

    /**
     * 更新体力不足商品信息
     */
    public function updateUnfitnessPayGoods(array $data, string $imgName)
    {
        $goodId = $data['id'];

        $gType = $this->gTypeMap[$imgName];

        self::createImportConfig($imgName);

        $this->payFixFields['g_type'] = $gType;
        $this->payFixFields['sku'] = $this->matchSKU($data['price']);

        if (!empty($data['ss_group'])) {
            $this->payFixFields['ss_group'] = $this->formatSSGroup($data['ss_group']);
        }

        if (!empty($data['props']['prizeJson'])) {
            $this->payFixFields['prize_json'] = $this->formatPrize($data['props']['prizeJson'] ?? []);
        }

        if (!empty($data['other_json'])) {
            $this->payFixFields['other_json'] = $this->formatPrize($data['other_json'] ?? []);
        }

        unset($data['id'], $data['props'], $data['img_name']);

        $data = array_merge($data, $this->payFixFields);

        //插入
        if (empty($goodId)) {
            $this->insertGoods($data);
        } else {
            $this->updateGoods($data, "id=$goodId");
        }
    }

    /**
     * 更新冲刺商品信息
     */
    public function updateSprintPayGoods(array $data)
    {
        $goodId = $data['id'];
        $data['life_time'] = 0;
        $data['discount'] = 0;
        $data['sku'] = $this->matchSKU($data['price']);
        $data['ss_group'] = $this->formatSSGroup($data['ss_group']);
        $data['prize_json'] = $this->formatPrize($data['props']['prizeJson'] ?? []);

        unset($data['id'], $data['props'], $data['img_name']);

        $this->updateGoods($data, "id=$goodId");
    }

    /**
     * 更新升级商品信息
     */
    public function updateUpgradePayGoods(array $data)
    {
        $goodId = $data['id'];
        $data['prize_json'] = $this->formatPrize($data['props']['prizeJson'] ?? []);
        $data['max_level'] = $data['min_level'];
        $data['sku'] = $this->matchSKU($data['price']);
        $data['other_json'] = json_encode([
            'showMultiple' => $data['showMultiple']
        ], JSON_NUMERIC_CHECK);

        //更新Json文件
        $this->updateUpgradeJson();

        $this->updateGoods($data, "id=$goodId");
    }

    /**
     * 更新礼包通用信息
     */
    public function updateGoodsCommonConf(array $data)
    {
        switch ($data['img_name']) {
            case self::IMG_NAME_SPRINT_PAY:
                oo::commonOprModel('config')->updateCon(self::IMG_NAME_SPRINT_PAY, "duration", $data['duration'], '冲刺礼包持续时间');   //持续时间
                oo::commonOprModel('config')->updateCon(self::IMG_NAME_SPRINT_PAY, "minLevel", $data['minLevel'], '冲刺礼包开放等级');   //持续时间
                break;
            case self::IMG_NAME_UPGRADE_PAY:
                oo::commonOprModel('config')->updateCon(self::IMG_NAME_UPGRADE_PAY, "duration", $data['duration'], '升级礼包持续时间');   //持续时间

                //更新Json文件
                $this->updateUpgradeJson();
                break;
        }
    }

    /**
     * 更新冲刺商品信息
     */
    public function importGoodsConfig($file, string $imgName): array
    {
        //获取表格数据
        $dataArray = $this->getExcelSheetsArray($file);
        $basicConfArray = $dataArray[0] ?? [];
        $rewardsConfArray = $dataArray[1] ?? [];
        $extraConfArray = $dataArray[2] ?? [];

        //根据imgName取导入数据的字段配置
        self::createImportConfig($imgName);

        $gType = $this->gTypeMap[$imgName];

        $this->payFixFields['g_type'] = $gType;

        $basicConf = $this->formatExcelBasicConf($basicConfArray);
        $rewardsConf = $this->formatExcelRewardConf($rewardsConfArray);
        $extraConf = $this->formatExcelExtraConf($extraConfArray);

        $formatGoodsConf = $this->matchGoodsConf($basicConf, $rewardsConf, $extraConf);

        //出现错误
        if ($formatGoodsConf[0] === -1) {
            return $formatGoodsConf;
        }

        //删除同一gtype的记录
        $sql = "DELETE FROM {$this->giftPackGoodsTable} WHERE g_type={$gType}";
        oo::commonOprDb('games')->query($sql);

        //插入新记录
        $sql = funs::db_intsertArrSQL($this->giftPackGoodsTable, $formatGoodsConf);
        oo::commonOprDb('games')->query($sql);

        //更新Json文件
        if (in_array($imgName, [self::IMG_NAME_UPGRADE_PAY])) {
            $this->updateUpgradeJson();
        }

        return [0, '操作成功'];
    }

    /**
     * 展示所有商品信息,通过gType
     * @param int $gType
     * @return array
     */
    public function showGoods(int $gType): array
    {
        $sql = "SELECT * FROM {$this->giftPackGoodsTable} where g_type={$gType};";
        $tableData = oo::commonOprDb('games')->getAll($sql, 1);

        foreach ($tableData as &$oneD) {
            $prizeJson = json_decode($oneD['prize_json'], true);
            $oneD['ss_group'] = json_decode($oneD['ss_group'], true);
            if (empty($oneD['ss_group']) || !is_array($oneD['ss_group'])) {
                $oneD['ssGroup'] = [];
            } else {
                foreach ($oneD['ss_group'] as $oneGroup) {
                    $oneD['ssGroup'][] = $this->ssGroupList[$oneGroup];
                }
            }
            $oneD = array_merge($oneD, json_decode($oneD['other_json'], true));

            $htmlStr = '<div>';
            foreach ($prizeJson as $onePrize) {
                $prizeStr = $this->matchPrizeInfo($onePrize);
                $htmlStr .= '<button style="margin-bottom: 5px" class="btn btn-outline btn-info btn-sm">' . $prizeStr . '</button><br>';
            }
            $htmlStr .= '</div>';
            $oneD['prizeJson'] = $htmlStr;
        }

        return $tableData;
    }

    /**
     * 展示通用配置信息
     * @param string $imgName
     * @return array
     */
    public function showCommonConf(string $imgName): array
    {
        switch ($imgName) {
            case self::IMG_NAME_SPRINT_PAY:
                $commonConf = [
                    "duration" => oo::commonOprModel('config')->getCon(self::IMG_NAME_SPRINT_PAY, "duration") ?? 0,   //持续时间
                    "minLevel" => oo::commonOprModel('config')->getCon(self::IMG_NAME_SPRINT_PAY, "minLevel") ?? 0,   //开放等级
                ];
                break;
            case self::IMG_NAME_UPGRADE_PAY:
                $commonConf = [
                    "duration" => oo::commonOprModel('config')->getCon(self::IMG_NAME_UPGRADE_PAY, "duration") ?? 0,   //持续时间
                ];
                break;
            default:
                $commonConf = [];

        }

        return $commonConf;
    }

    /**
     * 获取gType对应的view列表
     * @return array
     */
    public function getGTypeMap(): array
    {
        $sql = "select `g_type`, `en_name` FROM {$this->gTypeGoodsTable} where not isnull(`en_name`);";
        $gTypeArr = oo::commonOprDb('games')->getAll($sql, 1);

        $typeMap = [];
        foreach ($gTypeArr as $oneGType) {
            $typeMap[$oneGType['en_name']] = $oneGType['g_type'];
        }

        return $typeMap;
    }

    /**
     * 获取gType对应的view列表
     * @param string $imgName
     * @return array
     */
    public function getImgSkinList(string $imgName): array
    {
        if (in_array($imgName, [self::IMG_NAME_UNFITNESS_PAY, self::IMG_NAME_UPGRADE_PAY])) {
            return [];
        }

        $imgSkinList = oo::commonOprModel('config')->getActiveImgNameConfig($imgName)['content'] ?? [];

        $skinList = [];
        foreach ($imgSkinList as $oneSkin) {
            $skinList[$oneSkin['type']] = $oneSkin['name'];
        }

        return $skinList;
    }


    /**
     * 插入一条商品信息
     * @param array $data
     */
    private function insertGoods(array $data)
    {
        $this->filterFieldNull($this->giftPackGoodsTable, $data);
        $sql = funs::db_insertSQL($this->giftPackGoodsTable, $data);

//        error_log($sql);
        oo::commonOprDb('games')->query($sql);
    }

    /**
     * 更新商品信息
     * @param array $data
     * @param string $where
     */
    private function updateGoods(array $data, string $where)
    {
        $this->filterFieldNull($this->giftPackGoodsTable, $data);
        $sql = funs::db_updateSQL($this->giftPackGoodsTable, $data, $where);

//        error_log($sql);
        oo::commonOprDb('games')->query($sql);
    }


    /**
     * 匹配SKU，通过价格
     * @param float $price
     * @return string
     */
    private function matchSKU(float $price): string
    {
        //价格sku
        $skuList = oo::cfg('sku');

        foreach ($skuList as $oneSkuInfo) {
            if ($oneSkuInfo['price'] == $price) {
                return $oneSkuInfo['sku'];
            }
        }

        return '';
    }

    private function formatPrize(array $prizeArr): string
    {
        $prizeArr = array_values($prizeArr);

        foreach ($prizeArr as &$onePrize) {
            foreach ($onePrize as $key => &$value) {
                $value = intval($value);
            }
        }

        return json_encode($prizeArr);
    }

    private function formatSSGroup(array $ssGroup): string
    {
        return json_encode($ssGroup, JSON_NUMERIC_CHECK);
    }

    private function filterFieldNull(string $tableName, array &$data)
    {
        $tableNameArr = explode('.', $tableName);
        $fieldsInfo = oo::commonOprDb('games')->getAll("select COLUMN_NAME from information_schema.COLUMNS
                    where table_name = '{$tableNameArr[1]}' and table_schema = '{$tableNameArr[0]}'");
        $fieldArr = array_column($fieldsInfo, 'COLUMN_NAME');

        foreach ($data as $key => &$value) {
            if ($value === null || !in_array($key, $fieldArr)) {
                unset($data[$key]);
            }
        }
    }

    private function getExcelSheetsArray($file): array
    {
        $xlsReader = IOFactory::createReader('Excel2007');
        $xlsReader->setReadDataOnly(true);
        $xlsReader->setLoadSheetsOnly(true);

        $Sheets = $xlsReader->load($file['url']);
        $sheetsCnt = $Sheets->getSheetCount();

        $dataArray = [];
        for ($i = 0; $i < $sheetsCnt; $i++) {
            $tmpData = $Sheets->getSheet($i)->toArray() ?? [];
            foreach ($tmpData as $k => $item) {
                foreach ($item as $k1 => $value) {
                    $item[$k1] = trim($value);
                }
                $line = array_filter($item);
                if (empty($line)) unset($tmpData[$k]);
            }
            $dataArray[$i] = $tmpData;
        }
        return $dataArray;
    }

    private function formatExcelBasicConf($basicConfArray): array
    {
        $ssGroupReverse = array_flip($this->ssGroupList);

        $fieldArr = [];

        foreach ($basicConfArray[0] as $field) {
            if (is_null($field)) {
                continue;
            }
            $fieldArr[] = $this->basicFieldsMap[$field];
        }

        $recordArr = [];
        for ($i = 1; $i < count($basicConfArray); $i++) {
            $oneRecord = [];
            foreach ($basicConfArray[$i] as $index => $item) {
                if (is_null($item)) {
                    continue;
                }
                if ($fieldArr[$index] == "ss_group") {
                    foreach (explode(',', $item) as $groupName) {
                        $oneRecord['ss_group'][] = intval($ssGroupReverse[$groupName]);
                    }
                } else {
                    $oneRecord[$fieldArr[$index]] = $item;
                }
            }
            $recordArr[] = $oneRecord;
        }

        return $recordArr;
    }

    /**
     *  解析奖励配置
     * @param array $stagesRewardsArray
     * @return array
     */
    private function formatExcelRewardConf(array $stagesRewardsArray): array
    {
        $rewardsConf = [];
        for ($line = 1; $line < count($stagesRewardsArray); $line++) {
            $item = $stagesRewardsArray[$line];

            $rewardsTemp = ['uuid' => $item[0], 'prize_json' => []];
            $rewardList = [];

            //分割奖励
            array_shift($item);
            for ($index = 0; $index < count($item); $index++) {
                $div = intval($index / 3);
                $mod = $index % 3;

                $value = $item[$index];
                if ($mod == 0) {
                    if (empty($value)) {
                        break;
                    }
                    $rewardList[$div]['rewardName'] = $value;

                } elseif ($mod == 1) {
                    $rewardList[$div]['isFixNum'] = $value;
                } else {
                    $rewardList[$div]['rewardNum'] = $value;
                }
            }

            //格式化奖励
            foreach ($rewardList as $oneReward) {
                list($propsId, $skin) = $this->parseRewardTypeAndSkinId($oneReward['rewardName']);

                #非金币奖励，全部固定值奖励
                if (!in_array($oneReward['rewardName'], self::MultiNumTypeReward)) {
                    $oneReward['isFixNum'] = '是';
                }

                #固定值奖励 1 按等级取值 2
                $rtype = ($oneReward['isFixNum'] == '是') ? 1 : 2;

                #奖励数值
                $num = $oneReward['rewardNum'];

                $rewardsTemp['prize_json'][] = [
                    "propsId" => intval($propsId),
                    "num" => intval($num),
                    "rtype" => intval($rtype),
                    "skin" => intval($skin)
                ];
            }

            $rewardsConf[] = $rewardsTemp;
        }

        return $rewardsConf;
    }

    /**
     *  解析额外字段配置
     * @param $extraConfArray
     * @return array
     */
    private function formatExcelExtraConf($extraConfArray): array
    {
        if (empty($extraConfArray)) {
            return [];
        }

        $fieldArr = [];
        foreach ($extraConfArray[0] as $field) {
            $fieldArr[] = $this->extraFieldsMap[$field];
        }

        $extraConf = [];
        for ($i = 1; $i < count($extraConfArray); $i++) {
            $oneExtra = [];
            foreach ($extraConfArray[$i] as $index => $item) {
                $oneExtra[$fieldArr[$index]] = $item;
            }
            $extraConf[] = $oneExtra;
        }

        return $extraConf;
    }

    //合并匹配数组，根据唯一ID
    private function matchGoodsConf(array $basicConf, array $rewardsConf, array $extraConf): array
    {
        //表中的所有字段
        $tableNameArr = explode('.', otable::giftPackGoods());
        $fieldsInfo = oo::commonOprDb('games')->getAll("select COLUMN_NAME from information_schema.COLUMNS
                    where table_name = '{$tableNameArr[1]}' and table_schema = '{$tableNameArr[0]}'");
        $fieldArr = array_column($fieldsInfo, 'COLUMN_NAME');

        $allRecordInfo = [];
        foreach ($basicConf as $oneBaseConf) {
            $matchTimes = 0;
            foreach ($rewardsConf as $index => $oneRewardConf) {
                //匹配上了
                if ($oneBaseConf['uuid'] == $oneRewardConf['uuid']) {
                    $matchTimes++;

                    //检查奖励的合法性
                    foreach ($oneRewardConf['prize_json'] as $onePrize) {
                        if (empty($onePrize['propsId'])) {
                            $jsonStr = json_encode($onePrize);
                            return [-1, "唯一ID：{$oneRewardConf['uuid']},存在不合法的奖励项，propInfo：{$jsonStr}"];
                        }
                    }

                    $oneRecordInfo = $this->formatRecordInfo($fieldArr, array_merge($oneBaseConf, $oneRewardConf));

                    $price = $oneRecordInfo['price'];
                    $oneRecordInfo['sku'] = $this->matchSKU($price);
                    if (empty($oneRecordInfo['sku'])) {
                        return [-1, "唯一ID：{$oneRewardConf['uuid']},价格对应的sku不存在:'{$price}'"];
                    }

                    //额外字段
                    if (!empty($extraConf)) {
                        foreach ($extraConf as $oneExtra) {
                            if ($oneBaseConf['uuid'] == $oneExtra['uuid']) {
                                unset($oneExtra['uuid']);
                                $oneRecordInfo['other_json'] = $oneExtra;
                            }
                        }
                    }

                    unset($oneRecordInfo['id']);
                    $allRecordInfo[] = $oneRecordInfo;
                }
            }
            //没匹配到奖励
            if (empty($matchTimes)) {
                return [-1, "唯一ID：{$oneBaseConf['uuid']},未匹配到奖励"];
            }
        }

        return $allRecordInfo;
    }

    # 通过奖励名 解析奖励类型以及皮肤id
    private function parseRewardTypeAndSkinId($rewardName): array
    {
        foreach ($this->propsConfig as $oneProps) {
            //对比奖励名
            if ($oneProps['name'] == $rewardName) {
                return [$oneProps['id'], ''];
            }

            if (empty($oneProps['skinList'])) {
                continue;
            }

            //有皮肤列表时，对比皮肤名
            foreach ($oneProps['skinList'] as $oneSkin) {
                if ($oneSkin['name'] == $rewardName) {
                    return [$oneProps['id'], $oneSkin['id']];
                }
            }
        }

        return ['', ''];
    }

    private function formatRecordInfo(array $fieldArr, array $recordInfo): array
    {
        $dataInfo = array_merge($this->payFixFields, $recordInfo);
        $recordFormat = [];
        foreach ($fieldArr as $field) {
            if (isset($dataInfo[$field])) {
                $recordFormat[$field] = $dataInfo[$field];
            }
        }
        return $recordFormat;
    }

    private function matchPrizeInfo($onePrize): string
    {
        $name = '';
        foreach ($this->propsConfig as $oneProp) {
            if ($oneProp['id'] == $onePrize['propsId']) {
                if (empty($onePrize['skin'])) {
                    $name = $oneProp['name'];
                    break;
                }
                foreach ($oneProp['skinList'] as $oneSkin) {
                    if ($onePrize['skin'] == $oneSkin['id']) {
                        $name = $oneSkin['name'];
                        break;
                    }
                }
            }
        }
        return $name . '：' . $onePrize['num'] . ($onePrize['rtype'] == 2 ? '倍' : '');
    }

    private function createImportConfig(string $imgName)
    {
        $payFixFields = [];

        switch ($imgName) {
            case self::IMG_NAME_SPRINT_PAY:
                $payFixFields = [
                    'desc' => '冲刺礼包商品',
                    'other_json' => '[]',
                    'ss_group' => '[]',
                    'status' => 1,
                    'gid' => 500000,
                ];

                break;
            case self::IMG_NAME_UNFITNESS_PAY:
                $payFixFields = [
                    'gid' => 510000,
                    'desc' => '体力不足礼包商品',
                    'ss_group' => '[]',
                    'other_json' => '[]',
                    'status' => 1,
                ];
                break;
            case self::IMG_NAME_UPGRADE_PAY:
                $payFixFields = [
                    'desc' => '升级礼包商品',
                    'other_json' => '[]',
                    'ss_group' => '[]',
                    'status' => 1,
                    'gid' => 520000,
                ];

                break;
        }

        $this->payFixFields = $payFixFields;
    }

    private function updateUpgradeJson()
    {
        $filename = 'GiftUpLevelConfig' . time() . '.json';

        $config['list'] = self::createUpgradeJson();

        //持续时间
        $duration = oo::commonOprModel('config')->getCon(self::IMG_NAME_UPGRADE_PAY, "duration") ?? 0;

        $config['expiryTime'] = 60 * $duration;
        oo::commonOprModel("json")->SaveJson($config, $filename);
        oo::commonOprModel("json")->setStaticConfig("GiftUpLevelConfig", $filename);
    }

    private function createUpgradeJson(): array
    {
        $imgName = self::IMG_NAME_UPGRADE_PAY;
        $gType = $this->gTypeMap[$imgName];

        $sql = "SELECT * FROM {$this->giftPackGoodsTable} where g_type={$gType};";
        $tableData = oo::commonOprDb('games')->getAll($sql, 1);

        $jsonInfo = [];
        foreach ($tableData as $index => $oneRecord) {
            $jsonInfo[] = [
                "section_id" => $index,
                "gid" => intval($oneRecord['gid']),
                "start_level" => intval($oneRecord['min_level']),
                "end_level" => intval($oneRecord['max_level']),
                "multi" => intval(json_decode($oneRecord['other_json'], true)['showMultiple'])
            ];
        }

        return $jsonInfo;
    }
}