<?php

/**
 * CarExteriorRefitLogic.php
 * 赛车外观改装
 */

namespace Game\Logic;

use Framework\Lib\Utils;
use Framework\Log\LogMark;
use Framework\MVC\ModelManager;
use Framework\Network\SendMessage;
use Framework\DB\Handler\PlayerDBHandler;
use Framework\Logic\TemplateHelp;
use Game\Constant\CarExteriorRefitDefine;
use Game\Constant\ClientErrorCode;
use Game\Constant\ConstTemplate\TemplateAppearance;
use Game\Constant\ConstTemplate\TemplateConst;
use Game\Constant\ConstTemplate\TemplateNumber;
use Game\Constant\ConstTemplate\TemplateShieldNumber;
use Game\Constant\EventTypeDefine;
use Game\Constant\GameConstantDefine;
use Game\Constant\GameErrorCode;
use Game\Constant\ModelTypeDefine;
use Game\Constant\TemplateDefine;
use Game\Data\AccountData;
use Game\Data\Car\CarData;
use Game\Data\Car\CarExteriorData;
use Game\Data\CarExteriorRefitData;
use Game\Model\AccountModel;
use Game\Model\Car\CarExteriorRefitModel;
use Game\Model\Car\CarModel;
use Game\Protobuf\GCGetLicence;
use Game\Protobuf\PacketId;

trait CarExteriorRefitLogic {
    use PlayerDBHandler;
    use TemplateHelp;
    use CarLogic;
    use AccountLogic;
    use EventConditionLogic;
    use RankLogic;

    // 获取车牌号
    public function getLicence():bool {
        $licenceArr = [];
        /**
         * @var CarExteriorRefitModel $refitModel
         */
        $GCLicence = new GCGetLicence();
        $refitModel = ModelManager::getInstance()->getModel(ModelTypeDefine::CAR_EXTERIOR_REFIT);

        /**
         * @var AccountModel $account
         */
        $account = ModelManager::getInstance()->getModel(ModelTypeDefine::ACCOUNT);
        $account->searchAccount($arr);
        $playerNum = $arr[AccountData::DB_LICENCE_NUM];
        $playerDate = $arr[AccountData::DB_LICENCE_DATE];

        $currentTime = date('Y-m-d',  Utils::getServerTimestamp());

        // 判断抽取数量
        $numMax = $this->getTerm(TemplateDefine::TYPE_CONST,
            TemplateConst::Const_Licence_Max, "Const_num");

        if(empty($playerDate) || $currentTime > $playerDate) {
            $this->savePlayerLicenceNum(1);
            $this->savePlayerLicenceDate($currentTime);
        } else {
            if($playerNum >= $numMax) {
                // 返回已到当日抽取车牌上限
                $GCLicence->setCode(ClientErrorCode::EXTERIOR_LICENCE_IS_MAX);
                $GCLicence->setLincence([]);
                SendMessage::getInstance()->sendClient(
                    PacketId::GC_GetLicence, $GCLicence);
                return false;
            }
            $playerNum += 1;
            $this->savePlayerLicenceNum($playerNum);
        }

        for($i = 0; $i <= $refitModel::RAND_NUM; $i++) {
            $licenceStr = '';
            $licence = array_rand($refitModel::RAND_LICENCE, $refitModel::LICENCE_NUM);
            foreach($licence as $k) {
                $licenceStr .= $refitModel::RAND_LICENCE[$k];
            }
            $isShield = false;
            $isNumber = false;
            // 判重
            if(in_array($licenceStr, $licenceArr)) {
                continue;
            }

            // 判断屏蔽字
            for($j = 1; $j <= $refitModel::NUMBER_SHIELD_INDEX; $j ++) {
                $cfg = $this->getTitle(TemplateDefine::TYPE_SHIELD_NUMBER, $j);
                if(is_null($cfg)) {
                    break;
                }
                if(strPos($licenceStr, $cfg[TemplateShieldNumber::ShieldNum]) !== false) {
                    $isShield = true;
                    break;
                }
            }

            // 判断特殊号码不参与筛选
            for($k = 1; $k <= $refitModel::NUMBER_INDEX; $k ++) {
                $cfg = $this->getTitle(TemplateDefine::TYPE_NUMBER, $k);
                if(is_null($cfg)) {
                    break;
                }
                if(strPos($licenceStr, $cfg[TemplateNumber::Number]) !== false) {
                    $isNumber = true;
                    break;
                }
            }

            // 如果包含屏蔽字或者特殊号码 则重新随机
            if($isShield || $isNumber) {
                continue;
            }

            $licenceArr[] = $licenceStr;
            if(count($licenceArr) >= $refitModel::LICENCE_COUNT) {
                break;
            }
        }

        $GCLicence->setCode(ClientErrorCode::CLIENT_SUCCESS);
        $GCLicence->setLincence($licenceArr);
        SendMessage::getInstance()->sendClient(
            PacketId::GC_GetLicence, $GCLicence);
        return true;
    }
    /**
     * @desc 创建外观改造数据
     * @param int $carUID
     * @param int $tplID
     * @param string $params
     * @return bool
     */
    public function createExteriorRefitData(int $carTplID, int $refitID): bool
    {
        /**
         * @var CarExteriorRefitModel $refitModel
         */
        $refitModel = ModelManager::getInstance()->getModel(ModelTypeDefine::CAR_EXTERIOR_REFIT);
        $refit = $refitModel->createExteriorRefit($carTplID, $refitID);
        if(is_null($refit)) {
            LogMark::getInstance()->markError(
                GameErrorCode::DATA_CREATE_ERROR,
                '[exteriorRefitLogic] create car exterior refit error!',
                ['carID' => $carTplID, 'refitID' => $refitID]
            );
            return false;
        }

        // 如果是bind 赛车的 则添加到赛车上
        $cfg = $this->getTitle(TemplateDefine::TYPE_APPEARANCE, $refitID);
        $carUID = $this->searchCarDataByCarID($carTplID)->uid;
        if(CarExteriorRefitDefine::REFIT_MAP[$cfg[TemplateAppearance::Type]] === CarExteriorRefitDefine::BIND_CAR) {
            if(!$refitModel->addCarExteriorData($carUID,$cfg[TemplateAppearance::Type], $refit->uid, '')) {
                LogMark::getInstance()->markError(
                    GameErrorCode::DATA_CREATE_ERROR,
                    '[exteriorRefitLogic] create car exterior refit bind car error!',
                    ['carID' => $carTplID, 'refitID' => $refitID]
                );
                return false;
            }
        }

        // TODO::给客户端回数据
        $refitModel->sendPacket();

        return true;
    }

    // 赛车外观改装
    public function carExteriorRefit(int $carUID, int $type, int $refitID, string $params): bool {
        $exteriorType = CarExteriorRefitDefine::REFIT_MAP[$type];
        switch($exteriorType) {
            case CarExteriorRefitDefine::BIND_CAR:
                if(!$this->bindCarExteriorRefit($carUID, $type, $refitID)) {
                    LogMark::getInstance()->markError(
                        GameErrorCode::DATA_CREATE_ERROR,
                        '[exteriorRefitLogic] create car exterior refit error!',
                        ['carUID' => $carUID, 'type' => $type, 'refitID' => $refitID]
                    );
                    return false;
                }
                break;
            case CarExteriorRefitDefine::NORMAL:
                if(!$this->normalExteriorRefit($carUID, $type, $refitID)) {
                    LogMark::getInstance()->markError(
                        GameErrorCode::DATA_CREATE_ERROR,
                        '[exteriorRefitLogic] create car exterior refit error!',
                        ['carUID' => $carUID, 'type' => $type, 'refitID' => $refitID]
                    );
                    return false;
                }
                break;
            case CarExteriorRefitDefine::SPECIAL:
                if(!$this->specialExteriorRefit($carUID, $type, $refitID, $params)) {
                    LogMark::getInstance()->markError(
                        GameErrorCode::DATA_CREATE_ERROR,
                        '[exteriorRefitLogic] create car exterior refit error!',
                        ['carUID' => $carUID, 'type' => $type, 'refitID' => $refitID, 'params' => $params]
                    );
                    return false;
                }
                break;
            default:
                break;
        }
        $this->sendMessage->setCode(ClientErrorCode::CLIENT_SUCCESS);
        $this->sendMessage->setCarUID($carUID);
        $this->sendMessage->setType($type);
        $this->sendMessage->setRefitID($refitID);
        SendMessage::getInstance()->sendClient(
            PacketId::GC_CarExteriorRefit, $this->sendMessage);
        $this->triggerCarExteriorRefitEvent($carUID, $type);
        $this->syncMineRankInfo();
        return true;
    }

    // 绑定车辆数据修改 皮肤 车漆 灯带  tplID*getTime*1 | tplID*getTime ...
    public function bindCarExteriorRefit(int $carUID, int $type, int $refitID): bool {
        if(!$this->checkExteriorRefitIsValid($carUID, $refitID)) {
            $this->sendMessage->setCode(ClientErrorCode::EXTERIOR_EXTERIOR_REFIT_NOT_USE);
            SendMessage::getInstance()->sendClient(
                PacketId::GC_CarExteriorRefit, $this->sendMessage);
            return false;
        }

        /**
         * @var CarExteriorRefitModel $refitModel
         */
        $refitModel = ModelManager::getInstance()->getModel(ModelTypeDefine::CAR_EXTERIOR_REFIT);
        if(!$refitModel->changeBindCarExteriorData($carUID, $type, $refitID)) {
            LogMark::getInstance()->markError(
                GameErrorCode::DATA_CREATE_ERROR,
                '[exteriorRefitLogic] car normal exterior refit change error!',
                ['carUID' => $carUID, 'type' => $type, 'refitID' => $refitID]
            );
        }
        return true;
    }

    // 常规车辆数据修改
    public function normalExteriorRefit(int $carUID, int $type, int $refitID): bool {

        if(!$this->checkExteriorRefitIsValid($carUID, $refitID)) {
            $this->sendMessage->setCode(ClientErrorCode::EXTERIOR_EXTERIOR_REFIT_NOT_USE);
            SendMessage::getInstance()->sendClient(
                PacketId::GC_CarExteriorRefit, $this->sendMessage);
            return false;
        }

        /**
         * @var CarExteriorRefitModel $refitModel
         */
        $refitModel = ModelManager::getInstance()->getModel(ModelTypeDefine::CAR_EXTERIOR_REFIT);
        if(!$refitModel->changeCarExteriorData($carUID, $type, $refitID)) {
            LogMark::getInstance()->markError(
                GameErrorCode::DATA_CREATE_ERROR,
                '[exteriorRefitLogic] car normal exterior refit change error!',
                ['carUID' => $carUID, 'type' => $type, 'refitID' => $refitID]
            );
        }
        // 禁用部位校验
        return true;
    }

    // 特殊外观改装处理
    public function specialExteriorRefit(int $carUID, int $type, int $refitID, string $params): bool {

        if(!$this->checkExteriorRefitIsValid($carUID, $refitID)) {
            $this->sendMessage->setCode(ClientErrorCode::EXTERIOR_EXTERIOR_REFIT_NOT_USE);
            SendMessage::getInstance()->sendClient(
                PacketId::GC_CarExteriorRefit, $this->sendMessage);
            return false;
        }

        /**
         * @var CarExteriorRefitModel $refitModel
         */
        $refitModel = ModelManager::getInstance()->getModel(ModelTypeDefine::CAR_EXTERIOR_REFIT);

        // 挂饰修改    erID*position
        if(!$refitModel->changeCarExteriorOrnaments($carUID, $type, $refitID, $params)) {
            LogMark::getInstance()->markError(
                GameErrorCode::DATA_CREATE_ERROR,
                '[exteriorRefitLogic] car special exterior refit change error!',
                ['carUID' => $carUID, 'type' => $type, 'refitID' => $refitID]
            );
        }
        // 禁用部位校验
        // 皮肤和车漆不兼容
        return true;
    }

    // 车贴增加
    public function addExteriorRefit(int $carUID, int $type, int $refitID, string $params, int $num): bool {
        /**
         * @var CarExteriorRefitModel $refitModel
         */
        $refitModel = ModelManager::getInstance()->getModel(ModelTypeDefine::CAR_EXTERIOR_REFIT);

        // 挂饰修改    erID*num*position|
        if(!$refitModel->addExteriorRefitModel($carUID, $type, $refitID, $params, $num)) {
            LogMark::getInstance()->markError(
                GameErrorCode::DATA_CREATE_ERROR,
                '[exteriorRefitLogic] car special exterior refit add error!',
                [
                    'carUID' => $carUID, 'type' => $type, 'refitID' => $refitID,
                    'params' => $params, 'num' => $num
                ]
            );
            $refitModel->sendAddExteriorRefitPacket();
            return false;
        }

        // 禁用部位校验
        // 皮肤和车漆不兼容
        $this->triggerCarExteriorRefitEvent($carUID, $type);
        return true;
    }

    // 检测是否可以使用
    private function checkExteriorRefitIsValid(int $carUID, $refitID = 0, $createTplID = 0): bool {
        /**
         * @var CarExteriorRefitModel $refitModel
         */
        $refitModel = ModelManager::getInstance()->getModel(ModelTypeDefine::CAR_EXTERIOR_REFIT);

        $car = $this->getCarByCarUID($carUID);
        if(is_null($car)) {
            LogMark::getInstance()->markError(
                GameErrorCode::DATA_CREATE_ERROR,
                '[exteriorRefitLogic] check is valid exterior refit search car error!',
                ['carUID' => $carUID, 'refitID' => $refitID]
            );
            return false;
        }
        $cfg = $this->getTitle(TemplateDefine::TYPE_REFIT, $car->carID);
        if(is_null($cfg)) {
            LogMark::getInstance()->markError(
                GameErrorCode::DATA_CREATE_ERROR,
                '[exteriorRefitLogic] get car cfg info error!',
            );
            return false;
        }
        if($refitID === 0) {
            $tplID = $createTplID;
        } else {
            $refit = $refitModel->getExteriorRefitData($refitID);
            $tplID = $refit->tplID;
        }

        // 改装件为车牌号时 不校验
        if($tplID === 0) {
            return true;
        }

        $erCfg = $this->getTitle(TemplateDefine::TYPE_APPEARANCE, $tplID);

        if(!isset(CarExteriorRefitDefine::DB_REFIT_CHECK_MAP[$erCfg[TemplateAppearance::Type]])) {
            return true;
        }

        $arr = $cfg[CarExteriorRefitDefine::DB_REFIT_CHECK_MAP[$erCfg[TemplateAppearance::Type]]];

        return !(empty($arr) || !in_array($tplID, $arr));
    }

    // 改装删除
    public function exteriorRefitDel(int $carUID, int $type, int $refitID, int $num): bool {
        /**
         * @var CarExteriorRefitModel $refitModel
         */
        $refitModel = ModelManager::getInstance()->getModel(ModelTypeDefine::CAR_EXTERIOR_REFIT);
        $exteriorType = CarExteriorRefitDefine::REFIT_MAP[$type];
        switch($exteriorType) {
            case CarExteriorRefitDefine::BIND_CAR:
                if(!$refitModel->delBindCarExteriorRefit($carUID, $type, $refitID)) {
                    LogMark::getInstance()->markError(
                        GameErrorCode::DATA_CREATE_ERROR,
                        '[exteriorRefitLogic] del car exterior refit of bind error!',
                        ['carUID' => $carUID, 'type' => $type, 'refitID' => $refitID]
                    );
                    return false;
                }
                break;
            case CarExteriorRefitDefine::NORMAL:
                if(!$refitModel->delNormalExteriorRefit($carUID, $type)) {
                    LogMark::getInstance()->markError(
                        GameErrorCode::DATA_CREATE_ERROR,
                        '[exteriorRefitLogic] del car exterior refit of normal error!',
                        ['carUID' => $carUID, 'type' => $type, 'refitID' => $refitID]
                    );
                    return false;
                }
                break;
            case CarExteriorRefitDefine::SPECIAL:
                if(!$refitModel->deleteCarExteriorData($carUID, $type, $refitID, $num)) {
                    LogMark::getInstance()->markError(
                        GameErrorCode::DATA_CREATE_ERROR,
                        '[exteriorRefitLogic] del car exterior refit of special error!',
                        ['carUID' => $carUID, 'type' => $type, 'refitID' => $refitID]
                    );
                }
                break;
            default:
                break;
        }
        $this->triggerCarExteriorRefitEvent($carUID, $type);
        return true;
    }


    // 贴纸修改
    public function exteriorRefitUpdate(int $carUID, int $type, int $refitID, string $params, int $num): bool {
        /**
         * @var CarExteriorRefitModel $refitModel
         */
        $refitModel = ModelManager::getInstance()->getModel(ModelTypeDefine::CAR_EXTERIOR_REFIT);

        // 挂饰修改    erID*position
        if(!$refitModel->updateCarExteriorData($carUID, $type, $refitID, $params, $num)) {
            LogMark::getInstance()->markError(
                GameErrorCode::DATA_CREATE_ERROR,
                '[exteriorRefitLogic] car special exterior refit change error!',
                ['carUID' => $carUID, 'type' => $type, 'refitID' => $refitID]
            );
        } else {
            $this->triggerCarExteriorRefitEvent($carUID, $type);
        }
        return true;
    }

    // 查询
    public function getCarExteriorRefitFormatData(int $carUID):string {
        /**
         * @var CarModel $carModel
         */
        $carModel = ModelManager::getInstance()->getModel(ModelTypeDefine::CAR);
        $car = $carModel->getCarExteriorRefitData($carUID);
        $data = [];
        if(empty($car)) {
            LogMark::getInstance()->markError(
                GameErrorCode::DATA_SEARCH_ERROR,
                '[exteriorRefitLogic] get car data error!',
                ['carUID' => $carUID]
            );
            return '';
        }
        foreach (CarExteriorData::DB_SAVE_MAP as $item) {
            if(!empty($car[$item])) {
                switch($item) {
                    case CarExteriorData::DB_STICKER:
                        $arr = $this->execStickerData($car[$item]);
                        break;
                    case CarExteriorData::DB_ORNAMENTS:
                        $arr = $this->execOrnamentsData($car[$item]);
                        break;
                    case CarExteriorData::DB_LICENCE:
                        $arr = $this->execLicenceData($car[$item]);
                        break;
                    case CarExteriorData::DB_SKIN:
                    case CarExteriorData::DB_PAINT:
                    case CarExteriorData::DB_LIGHT_STRIP:
                        $arr = $this->execBindCarData($car[$item]);
                        break;
                    default:
                        $arr = $this->execNormalData($car[$item]);
                        break;
                }
                $data[$item] = $arr;
            }
        }
        return json_encode($data);
    }

    public function execStickerData(string $refit):array {
        /**
         * @var CarExteriorRefitModel $refitModel
         */
        $refitModel = ModelManager::getInstance()->getModel(ModelTypeDefine::CAR_EXTERIOR_REFIT);
        $resArr = [];
        $arrRefit = json_decode($refit, true);
        foreach($arrRefit as $item) {
            $exteriorRefit = $refitModel->getExteriorRefitData($item[CarExteriorData::DB_UID]);
            if(!is_null($exteriorRefit)) {
                $resArr[] = [
                    CarExteriorRefitData::TPL_ID => $exteriorRefit->tplID,
                    CarExteriorRefitData::PARAMS => $item[CarExteriorData::DB_POSITION],
                ];
            }
        }
        return $resArr;
    }
    public function execLicenceData(string $refit):array {
        /**
         * @var CarExteriorRefitModel $refitModel
         */
        $refitModel = ModelManager::getInstance()->getModel(ModelTypeDefine::CAR_EXTERIOR_REFIT);
        $res = [];
        $exteriorRefit = $refitModel->getExteriorRefitData($refit);
        if(!is_null($exteriorRefit)) {
            $res = [
                CarExteriorRefitData::TPL_ID => $exteriorRefit->tplID,
                CarExteriorRefitData::PARAMS => $exteriorRefit->params,
            ];
        }
        return $res;
    }

    public function execOrnamentsData(string $refit):array {
        /**
         * @var CarExteriorRefitModel $refitModel
         */
        $refitModel = ModelManager::getInstance()->getModel(ModelTypeDefine::CAR_EXTERIOR_REFIT);
        $resArr = [];
        $arr = json_decode($refit, true);
        $exteriorRefit = $refitModel->getExteriorRefitData($arr[CarExteriorData::DB_UID]);
        if(!is_null($exteriorRefit)) {
            $resArr = [
                CarExteriorRefitData::TPL_ID => $exteriorRefit->tplID,
                CarExteriorRefitData::PARAMS => $arr[CarExteriorData::DB_POSITION],
            ];
        }
        return $resArr;
    }

    public function execBindCarData(string $refit):int {
        /**
         * @var CarExteriorRefitModel $refitModel
         */
        $refitModel = ModelManager::getInstance()->getModel(ModelTypeDefine::CAR_EXTERIOR_REFIT);
        $res = 0;
        $arrRefit = json_decode($refit, true);
        foreach($arrRefit as $item) {
            if($item[CarExteriorData::DB_IS_USE] === CarExteriorData::DB_EXTERIOR_TRUE) {
                $exteriorRefit = $refitModel->getExteriorRefitData($item[CarExteriorData::DB_UID]);
                if(!is_null($exteriorRefit)) {
                    $res = $exteriorRefit->tplID;
                }
            }
        }
        return $res;
    }
    public function execNormalData(string $refit):int {
        /**
         * @var CarExteriorRefitModel $refitModel
         */
        $refitModel = ModelManager::getInstance()->getModel(ModelTypeDefine::CAR_EXTERIOR_REFIT);
        $res = 0;
        $exteriorRefit = $refitModel->getExteriorRefitData($refit);
        if(!is_null($exteriorRefit)) {
             $res = $exteriorRefit->tplID;
        }
        return $res;
    }

    private function triggerCarExteriorRefitEvent(int $carUID, int $type)
    {
        $car = $this->getCarByCarUID($carUID);
        // 触发任务
        $eventData = array(
            GameConstantDefine::EVENT_KEY_NUM => 1,
            GameConstantDefine::EVENT_KEY_CAR_REFIT_SYS_ID => $type,    //改装类型
            GameConstantDefine::EVENT_KEY_CAR_ID => $car->carID
        );
        $this->triggerEvent(EventTypeDefine::EVENT_TYPE_TASK_CAR_EXTERIOR_REFIT, $eventData);
        $this->addEventConditionValue(
            $this->getCarExteriorRefitKey($car->carID, $type),
            1
        );
    }
}
