<?php

/**
 * 大乱斗活动
 */

namespace Game\Logic\Activity;

use Framework\Lib\Utils;
use Framework\Log\LogMark;
use Framework\MVC\ModelManager;
use Game\Constant\ActivityDefine;
use Game\Constant\ClientErrorCode;
use Game\Constant\ConstTemplate\TemplateConst;
use Game\Constant\ConstTemplate\TemplateScrimmageCar;
use Game\Constant\GameConstantDefine;
use Game\Constant\GameErrorCode;
use Game\Constant\ModelTypeDefine;
use Game\Constant\TemplateDefine;
use Game\Data\PvpPacket\PvpMsgData;
use Game\Data\AccountData;
use Game\Data\Room\ScuffleRoomData;
use Game\Logic\AccountLogic;
use Game\Logic\CommonConstLogic;
use Game\Logic\GenerateAiLogic;
use Game\Model\Activity\ScuffleModel;
use Game\Model\Room\ScuffleRoomModel;
use Game\Protobuf\AIInfo;
use Game\Protobuf\CarShow;
use Game\Protobuf\GCCancelReplaceCarApply;
use Game\Protobuf\GCScuffleReplaceCarApply;
use Game\Protobuf\GCScuffleReplaceCarResult;
use Game\Protobuf\PacketId;
use Game\Protobuf\PlayerInfo;
use Game\Protobuf\PlayerShow;

trait ScuffleLogic
{
    use AccountLogic;
    use CommonConstLogic;
    use GenerateAiLogic;

    //检查活动是否开启--进入房间,开始匹配,切换模式时检查
    public function checkScuffleIsOpen(): bool
    {
        $commonConst = $this->getCommonConstData();
        return $commonConst[GameConstantDefine::COMMON_KEY_ACTIVITY_SCUFFLE_STATUS] == ActivityDefine::ACTIVITY_STATUS_DOING;
    }

    //随机车辆--排除自己和队友驾驶的和公共池
    private function getRandomScuffleCar(array $hasCarList): int
    {
        $gl = lcg_value();
        $config = $this->getTable(TemplateDefine::TYPE_SCUFFLE_CAR);
        $rollCarId = null;
        $tmpGl = 0;
        foreach ($config as $carId => $data) {
            $tmpGl += $data[TemplateScrimmageCar::Probability];
            if (in_array($carId, $hasCarList)) {
                continue;
            }
            if ($tmpGl >= $gl) {
                $rollCarId = $carId;
                break;
            }
        }
        if (is_null($rollCarId)) {
            LogMark::getInstance()->markError(
                GameErrorCode::ACTIVITY_SCUFFLE_ROLL_CAR_ERROR,
                "[ScuffleLogic] getRandomScuffleCar roll car fail, roll gl:{$gl}",
                $hasCarList
            );
            $rollCarId = array_key_last($config);
        }
        return $rollCarId;
    }

    /**
     * 创建大乱斗房间
     * @param array $msgInfo pvpPack->dealMatchingResult
     * @param int $matchUid ==roomId
     * @return array
     */
    public function createScuffleRoom(array $msgInfo, int $matchUid): array
    {
        $haveCarPool1 = $haveCarPool2 = array();
        $scuffleRoomData = array(
            ScuffleRoomData::ROOM_ID => $matchUid,
            ScuffleRoomData::MAP_ID => $msgInfo[PvpMsgData::MAP_ID],
            ScuffleRoomData::CREATE_TIME => Utils::getServerTimestamp(),
            ScuffleRoomData::PUBLIC_CAR_POOL_1 => json_encode(ScuffleRoomData::initPublicCarPool()),
            ScuffleRoomData::PUBLIC_CAR_POOL_2 => json_encode(ScuffleRoomData::initPublicCarPool()),
        );
        $playerList = array();
        $aiList = array();
        //根据队伍 随机车辆
        foreach ($msgInfo[PvpMsgData::PLAYER_LIST] as $player) {
            //将玩家数据转为PlayerInfo的protobuf
            $newPlayer = $this->playerArrToProtobuf(
                $player,
                //随机玩家车
                $this->rollPlayerCar($player[PvpMsgData::GROUP_ID],$haveCarPool1, $haveCarPool2)
            );
            $scuffleRoomData[$player[PvpMsgData::PLAYER_ID]] = $newPlayer->serializeToJsonString();
            //修改player CarShow
            $carShow = new CarShow();
            $carShow->setCarTplID($newPlayer->getCarTplId())
                ->setProficiencyLv($newPlayer->getProficiencyLv())
                ->setProficiency($newPlayer->getProficiency())
                ->setExteriorRefit($newPlayer->getExteriorRefit());
            $player[PvpMsgData::CAR_SHOW] = $carShow;
            $playerList[] = $player;
        }
        foreach ($msgInfo[PvpMsgData::AI_INFO] as $AIPlayer) {
            /**
             * @var AIInfo $AIPlayer
             */
            //随机AI车
            $newAi = $this->rollAICar(
                $AIPlayer,$haveCarPool1, $haveCarPool2);
            $scuffleRoomData[$AIPlayer->getPlayerId()] = $newAi->serializeToJsonString();
            $aiList[] = $newAi;
        }
        $scuffleRoomData[ScuffleRoomData::HAVE_CAR_POOL_1] = json_encode($haveCarPool1);
        $scuffleRoomData[ScuffleRoomData::HAVE_CAR_POOL_2] = json_encode($haveCarPool2);
        /**
         * @var ScuffleRoomModel $scuffleRoomModel
         */
        $scuffleRoomModel = ModelManager::getInstance()->getModel(ModelTypeDefine::ROOM_SCUFFLE);
        $scuffleRoomModel->createRoom($scuffleRoomData);
        return [$playerList, $aiList];
    }

    //将玩家数据转为PlayerInfo的protobuf
    private function playerArrToProtobuf(array $playerData, int $carId): PlayerInfo
    {
        /**
         * @var PlayerShow $playerShow
         */
        $playerShow = $playerData[PvpMsgData::PLAYER_SHOW];
        $player = new PlayerInfo();
        $player->setPlayerId($playerData[PvpMsgData::PLAYER_ID])
            ->setNickName($playerShow->getNickName())
            ->setHead($playerShow->getHead())
            ->setGroupID($playerData[PvpMsgData::GROUP_ID])
            ->setGender($playerShow->getGender())
            ->setCloth($playerShow->getCloth())
            ->setSkinColor($playerShow->getSkinColor())
            ->setPosition($playerData[PvpMsgData::POSITION])
            ->setContinuityWin(0);
        //TODO:自己有的车 熟练度 改装等 是否显示真实的
        $player->setCarTplId($carId)
            ->setExteriorRefit("[]")
            ->setProficiencyLv(1)
            ->setProficiency(0);
        return $player;
    }

    //随机玩家车辆
    private function rollPlayerCar(int $groupId, array &$haveCarPool1, array &$haveCarPool2): int
    {
        if ($groupId == 1) {
            $carId = $this->getRandomScuffleCar($haveCarPool1);
            $haveCarPool1[] = $carId;
        } else {
            $carId = $this->getRandomScuffleCar($haveCarPool2);
            $haveCarPool2[] = $carId;
        }
        return $carId;
    }

    //随机AI车
    private function rollAICar(AIInfo $AIPlayer, array &$haveCarPool1, array &$haveCarPool2): AIInfo
    {
        if ($AIPlayer->getGroupID() == 1) {
            $carId = $this->getRandomScuffleCar($haveCarPool1);
            $haveCarPool1[] = $carId;
        } else {
            $carId = $this->getRandomScuffleCar($haveCarPool2);
            $haveCarPool2[] = $carId;
        }
        //修改AI车信息
        $AIPlayer->setCarTplId($carId);
        $AIPlayer->setCarLevel(6);
        $AIPlayer->setExteriorRefit("[]");
        return $AIPlayer;
    }

    //使用骰子 随机车
    public function playerRollCar(): int
    {
        //获取玩家所在大乱斗房间信息
        $scuffleRoomData = $this->getScuffleRoomByJoinId();
        if (empty($scuffleRoomData)) {
            //房间错误
            LogMark::getInstance()->markDebug(
                "[ScuffleLogic] search scuffle room error"
            );
            return ClientErrorCode::SCUFFLE_ROOM_NOT_FOUND;
        }
        //检查准备时间
        $readyTime = $this->getTerm(
            TemplateDefine::TYPE_CONST,
            TemplateConst::Const_Scuffle_Ready_Time,
            TemplateConst::ConstNum);
        if (Utils::getServerTimestamp() > $scuffleRoomData[ScuffleRoomData::CREATE_TIME] + $readyTime) {
            return ClientErrorCode::SCUFFLE_ROOM_OVER_READY_TIME;
        }
        /**
         * @var ScuffleModel $scuffleModel
         */
        $scuffleModel = ModelManager::getInstance()->getModel(ModelTypeDefine::SCUFFLE);
        //检查是否正在进行换车申请
        $waitTime = $this->getTerm(
            TemplateDefine::TYPE_CONST,
            TemplateConst::Const_Scuffle_Replace_Player_Car_Wait_time,
            TemplateConst::ConstNum);
        $key = $scuffleModel->getPlayerId(). "#" . ScuffleRoomData::APPLY_KEY;
        if (isset($scuffleRoomData[$key])) {
            $applyData = json_decode($scuffleRoomData[$key], true);
            //正在申请
            if ($applyData[ScuffleRoomData::APPLY_STATUS] == ScuffleRoomData::APPLY_STATUS_WAIT ||
                $applyData[ScuffleRoomData::APPLY_TIME] + $waitTime > Utils::getServerTimestamp()
            ) {
                return ClientErrorCode::SCUFFLE_ROOM_REPLACE_CAR_WAITING;
            }
        }
        if (false == $scuffleModel->roll()) {
            //点数不足
            return ClientErrorCode::SCUFFLE_ROLL_POINT_NOT_ENOUGH;
        }
        $hasCarPool1 = json_decode($scuffleRoomData[ScuffleRoomData::HAVE_CAR_POOL_1], true);
        $hasCarPool2 = json_decode($scuffleRoomData[ScuffleRoomData::HAVE_CAR_POOL_2], true);
        $publicCarPool1 = json_decode($scuffleRoomData[ScuffleRoomData::PUBLIC_CAR_POOL_1], true);
        $publicCarPool2 = json_decode($scuffleRoomData[ScuffleRoomData::PUBLIC_CAR_POOL_2], true);
        $player = new PlayerInfo();
        $player->mergeFromJsonString($scuffleRoomData[$scuffleModel->getPlayerId()]);
        $oldCarId = $player->getCarTplId();
        //随机车
        $newCarId = $this->rollPlayerCar(
            $player->getGroupID(),
            $hasCarPool1,
            $hasCarPool2
        );
        $this->updatePlayerCarInfo($player, $newCarId);

        $updateData = array(
            $scuffleModel->getPlayerId() => $player->serializeToJsonString()
        );
        if ($player->getGroupID() == 1) {
            $this->addCarToPublicPool($oldCarId, $publicCarPool1);
            $updateData[ScuffleRoomData::HAVE_CAR_POOL_1] = json_encode($hasCarPool1);
            $updateData[ScuffleRoomData::PUBLIC_CAR_POOL_1] = json_encode($publicCarPool1);
            $publicCarPool = $publicCarPool1;
        } else {
            $this->addCarToPublicPool($oldCarId, $publicCarPool2);
            $updateData[ScuffleRoomData::HAVE_CAR_POOL_2] = json_encode($hasCarPool2);
            $updateData[ScuffleRoomData::PUBLIC_CAR_POOL_2] = json_encode($publicCarPool2);
            $publicCarPool = $publicCarPool2;
        }
        /**
         * @var ScuffleRoomModel $scuffleRoomModel
         */
        $scuffleRoomModel = ModelManager::getInstance()->getModel(ModelTypeDefine::ROOM_SCUFFLE);
        $scuffleRoomModel->updateScuffleRoom($scuffleRoomData[ScuffleRoomData::ROOM_ID], $updateData);
        //通知车辆变化
        $scuffleRoomModel->broadcastPlayerCarChange($player, array_keys($scuffleRoomData), $scuffleModel->getPlayerId());
        //通知公共车池变化
        $scuffleRoomModel->broadcastPublicCarPoolChange($player->getGroupID(), $publicCarPool, $scuffleRoomData);
        return ClientErrorCode::CLIENT_SUCCESS;
    }

    //使用公共车辆
    public function playerUsePublicPoolCar(int $index, int $carId): int
    {
        //获取玩家所在大乱斗房间信息
        $scuffleRoomData = $this->getScuffleRoomByJoinId();
        if (empty($scuffleRoomData)) {
            //房间错误
            LogMark::getInstance()->markDebug(
                "[ScuffleLogic] search scuffle room error"
            );
            return ClientErrorCode::SCUFFLE_ROOM_NOT_FOUND;
        }
        if ($index <= 0 && $index > 6) {
            return ClientErrorCode::SCUFFLE_ROOM_PUBLIC_POOL_INDEX_ERROR;
        }
        //检查准备时间
        $readyTime = $this->getTerm(
            TemplateDefine::TYPE_CONST,
            TemplateConst::Const_Scuffle_Ready_Time,
            TemplateConst::ConstNum);
        if (Utils::getServerTimestamp() > $scuffleRoomData[ScuffleRoomData::CREATE_TIME] + $readyTime) {
            return ClientErrorCode::SCUFFLE_ROOM_OVER_READY_TIME;
        }
        /**
         * @var ScuffleRoomModel $scuffleRoomModel
         */
        $scuffleRoomModel = ModelManager::getInstance()->getModel(ModelTypeDefine::ROOM_SCUFFLE);
        //检查是否正在进行换车申请
        $waitTime = $this->getTerm(
            TemplateDefine::TYPE_CONST,
            TemplateConst::Const_Scuffle_Replace_Player_Car_Wait_time,
            TemplateConst::ConstNum);
        $key = $scuffleRoomModel->getPlayerId(). "#" . ScuffleRoomData::APPLY_KEY;
        if (isset($scuffleRoomData[$key])) {
            $applyData = json_decode($scuffleRoomData[$key], true);
            //正在申请
            if ($applyData[ScuffleRoomData::APPLY_STATUS] == ScuffleRoomData::APPLY_STATUS_WAIT ||
                $applyData[ScuffleRoomData::APPLY_TIME] + $waitTime > Utils::getServerTimestamp()
            ) {
                return ClientErrorCode::SCUFFLE_ROOM_REPLACE_CAR_WAITING;
            }
        }
        $player = new PlayerInfo();
        $player->mergeFromJsonString($scuffleRoomData[$scuffleRoomModel->getPlayerId()]);
        if ($player->getGroupID() == 1) {
            $publicCarPool = json_decode($scuffleRoomData[ScuffleRoomData::PUBLIC_CAR_POOL_1], true);
            $publicCarPoolKey = ScuffleRoomData::PUBLIC_CAR_POOL_1;
        } else {
            $publicCarPool = json_decode($scuffleRoomData[ScuffleRoomData::PUBLIC_CAR_POOL_2], true);
            $publicCarPoolKey = ScuffleRoomData::PUBLIC_CAR_POOL_2;
        }
        if ($publicCarPool[$index][ScuffleRoomData::CAR_ID] == 0) {
            return ClientErrorCode::SCUFFLE_ROOM_PUBLIC_POOL_CAR_NOT_FOUND;
        }
        if ($publicCarPool[$index][ScuffleRoomData::POOL_CD] > Utils::getServerTimestamp()) {
            return ClientErrorCode::SCUFFLE_ROOM_PUBLIC_POOL_CAR_CD;
        }
        if ($publicCarPool[$index][ScuffleRoomData::CAR_ID] != $carId) {
            //选择的车 和公共车池数据不一致,通知同步一下
            $scuffleRoomModel->broadcastPublicCarPoolChange($player->getGroupID(), $publicCarPool, $scuffleRoomData);
            return ClientErrorCode::SCUFFLE_ROOM_PUBLIC_POOL_DATA_ERROR;
        }

        //更新公共车池
        $cdTime = $this->getTerm(
            TemplateDefine::TYPE_CONST,
            TemplateConst::Const_Scuffle_Public_Pool_CD,
            TemplateConst::ConstNum);
        $publicCarPool[$index][ScuffleRoomData::CAR_ID] = $player->getCarTplId();
        $publicCarPool[$index][ScuffleRoomData::POOL_CD] = Utils::getServerTimestamp() + $cdTime;
        //更新玩家车信息
        $this->updatePlayerCarInfo($player, $carId);

        $updateData = array(
            $publicCarPoolKey => json_encode($publicCarPool),
            $scuffleRoomModel->getPlayerId() => $player->serializeToJsonString()
        );
        $scuffleRoomModel->updateScuffleRoom($scuffleRoomData[ScuffleRoomData::ROOM_ID], $updateData);
        //通知车辆变化
        $scuffleRoomModel->broadcastPlayerCarChange($player, array_keys($scuffleRoomData), $scuffleRoomModel->getPlayerId());
        //通知公共车池变化
        $scuffleRoomModel->broadcastPublicCarPoolChange($player->getGroupID(), $publicCarPool, $scuffleRoomData);
        return ClientErrorCode::CLIENT_SUCCESS;
    }

    //申请交换赛车
    public function applyReplaceTargetCar(int $targetPlayerId, int $applyPlayerId): int
    {
        //检查对方id
        $scuffleRoomData = $this->getScuffleRoomByJoinId();
        if (empty($scuffleRoomData)) {
            //房间错误
            LogMark::getInstance()->markDebug(
                "[ScuffleLogic] search scuffle room error"
            );
            return ClientErrorCode::SCUFFLE_ROOM_NOT_FOUND;
        }
        //检查准备时间
        $readyTime = $this->getTerm(
            TemplateDefine::TYPE_CONST,
            TemplateConst::Const_Scuffle_Ready_Time,
            TemplateConst::ConstNum);
        if (Utils::getServerTimestamp() > $scuffleRoomData[ScuffleRoomData::CREATE_TIME] + $readyTime) {
            return ClientErrorCode::SCUFFLE_ROOM_OVER_READY_TIME;
        }
        if (!isset($scuffleRoomData[$targetPlayerId])) {
            return ClientErrorCode::SCUFFLE_ROOM_PLAYER_NOT_FOUND;
        }
        if ($targetPlayerId == $applyPlayerId) {
            return ClientErrorCode::SCUFFLE_ROOM_TARGET_PLAYER_ERROR;
        }
        //申请等待时间
        $waitTime = $this->getTerm(
            TemplateDefine::TYPE_CONST,
            TemplateConst::Const_Scuffle_Replace_Player_Car_Wait_time,
            TemplateConst::ConstNum);
        //换车CD时间
        $replaceCarCDTime = $this->getTerm(
            TemplateDefine::TYPE_CONST,
            TemplateConst::Const_Scuffle_Replace_Player_Car_CD_time,
            TemplateConst::ConstNum);
        //检查是否有正在进行的申请
        $key = $applyPlayerId. "#" . ScuffleRoomData::APPLY_KEY;
        $applyData = array();
        if (isset($scuffleRoomData[$key])) {
            $applyData = json_decode($scuffleRoomData[$key], true);
            //正在申请
            if ($applyData[ScuffleRoomData::APPLY_STATUS] == ScuffleRoomData::APPLY_STATUS_WAIT &&
                $applyData[ScuffleRoomData::APPLY_TIME] + $waitTime > Utils::getServerTimestamp()
            ) {
                return ClientErrorCode::SCUFFLE_ROOM_REPLACE_CAR_WAIT;
            }
            //申请完成
            if ($applyData[ScuffleRoomData::APPLY_STATUS] == ScuffleRoomData::APPLY_STATUS_OVER &&
                $applyData[ScuffleRoomData::APPLY_TIME] + $replaceCarCDTime > Utils::getServerTimestamp()
            ) {
                return ClientErrorCode::SCUFFLE_ROOM_REPLACE_CAR_CD;
            }
        }
        //检查对方是否正在申请
        $targetKey = $targetPlayerId . "#". ScuffleRoomData::APPLY_KEY;
        if (isset($scuffleRoomData[$targetKey])) {
            $targetData = json_decode($scuffleRoomData[$targetKey], true);
            if ($targetData[ScuffleRoomData::APPLY_STATUS] == ScuffleRoomData::APPLY_STATUS_WAIT ||
                $targetData[ScuffleRoomData::APPLY_TIME] + $waitTime > Utils::getServerTimestamp()
            ) {
                return ClientErrorCode::SCUFFLE_ROOM_REPLACE_CAR_TARGET_WAIT;
            }
        }
        $player = new PlayerInfo();
        $player->mergeFromJsonString($scuffleRoomData[$applyPlayerId]);
        /**
         * @var ScuffleRoomModel $scuffleRoomModel
         */
        $scuffleRoomModel = ModelManager::getInstance()->getModel(ModelTypeDefine::ROOM_SCUFFLE);
        //检查是否同组
        if ($this->checkIsAIPlayer($targetPlayerId)) {
            //AI
            $AIPlayer = new AIInfo();
            $AIPlayer->mergeFromJsonString($scuffleRoomData[$targetPlayerId]);
            if ($AIPlayer->getGroupID() != $player->getGroupID()) {
                return ClientErrorCode::SCUFFLE_ROOM_PLAYER_NOT_SAME_GROUP;
            }
            //记录申请信息
            $scuffleRoomModel->markApplyInfo($scuffleRoomData[ScuffleRoomData::ROOM_ID], $applyPlayerId, $targetPlayerId, $applyData);
            //不给AI发换车通知
            return ClientErrorCode::CLIENT_SUCCESS;
        }
        $targetPlayer = new PlayerInfo();
        $targetPlayer->mergeFromJsonString($scuffleRoomData[$targetPlayerId]);
        if ($targetPlayer->getGroupID() != $player->getGroupID()) {
            return ClientErrorCode::SCUFFLE_ROOM_PLAYER_NOT_SAME_GROUP;
        }
        //记录申请信息
        $scuffleRoomModel->markApplyInfo($scuffleRoomData[ScuffleRoomData::ROOM_ID], $applyPlayerId, $targetPlayerId, $applyData);
        //给对方发换车通知
        $playerData = $this->searchPlayerInfo($applyPlayerId);
        $applyMessage = new GCScuffleReplaceCarApply();
        $applyMessage->setApplyPlayerId($applyPlayerId);
        $applyMessage->setHead($playerData[AccountData::DB_HEAD]);
        $applyMessage->setNickName($playerData[AccountData::DB_NICK_NAME]);
        $applyMessage->setApplyTime(Utils::getServerTimestamp());
        $this->addPacket(PacketId::GC_ScuffleReplaceCarApply, $applyMessage, $targetPlayerId);
        return ClientErrorCode::CLIENT_SUCCESS;
    }

    //处理换车请求
    public function dealReplaceCarApply(bool $option, int $applyPlayerId, int $playerId): int
    {
        $scuffleRoomData = $this->getScuffleRoomByJoinId();
        if (empty($scuffleRoomData)) {
            //房间错误
            LogMark::getInstance()->markDebug(
                "[ScuffleLogic] search scuffle room error"
            );
            return ClientErrorCode::SCUFFLE_ROOM_NOT_FOUND;
        }
        LogMark::getInstance()->markInfo("[ScuffleLogic] scuffleRoomData", $scuffleRoomData);
        //检查准备时间
        $readyTime = $this->getTerm(
            TemplateDefine::TYPE_CONST,
            TemplateConst::Const_Scuffle_Ready_Time,
            TemplateConst::ConstNum);
        if (Utils::getServerTimestamp() > $scuffleRoomData[ScuffleRoomData::CREATE_TIME] + $readyTime) {
            return ClientErrorCode::SCUFFLE_ROOM_OVER_READY_TIME;
        }
        /**
         * @var ScuffleRoomModel $scuffleRoomModel
         */
        $scuffleRoomModel = ModelManager::getInstance()->getModel(ModelTypeDefine::ROOM_SCUFFLE);
        if ($option) {
            //同意换车
            //检查对方id
            if (!isset($scuffleRoomData[$applyPlayerId])) {
                return ClientErrorCode::SCUFFLE_ROOM_PLAYER_NOT_FOUND;
            }
            if ($applyPlayerId == $playerId) {
                return ClientErrorCode::SCUFFLE_ROOM_TARGET_PLAYER_ERROR;
            }
            //通知换车结果
            $this->sendReplaceCarResultToApplyPlayer($option, $applyPlayerId, $playerId);
            $player = new PlayerInfo();
            $applyPlayer = new PlayerInfo();
            $player->mergeFromJsonString($scuffleRoomData[$playerId]);
            $applyPlayer->mergeFromJsonString($scuffleRoomData[$applyPlayerId]);
            //互换车辆
            $playerCarId = $player->getCarTplId();
            $applyPlayerCarId = $applyPlayer->getCarTplId();
            $this->updatePlayerCarInfo($player, $applyPlayerCarId);
            $this->updatePlayerCarInfo($applyPlayer, $playerCarId);
            $updateData = array(
                $playerId => $player->serializeToJsonString(),
                $applyPlayerId => $applyPlayer->serializeToJsonString(),
            );
            LogMark::getInstance()->markInfo(
                "[ScuffleLogic] player:".$player->serializeToJsonString()
            );
            LogMark::getInstance()->markInfo(
                "[ScuffleLogic] applyPlayer:".$applyPlayer->serializeToJsonString()
            );
            //修改申请信息
            $key = $applyPlayerId ."#". ScuffleRoomData::APPLY_KEY;
            $data = json_decode($scuffleRoomData[$key], true);
            $data[ScuffleRoomData::APPLY_STATUS] = ScuffleRoomData::APPLY_STATUS_OVER;
            $data[$playerId] = ScuffleRoomData::APPLY_RESULT_STATUS_PASS;
            $updateData[$key] = json_encode($data);
            $targetKey = $playerId . "#". ScuffleRoomData::APPLY_KEY;
            $data = json_decode($scuffleRoomData[$targetKey], true);
            $data[ScuffleRoomData::APPLY_STATUS] = ScuffleRoomData::APPLY_STATUS_OVER;
            $data[$applyPlayerId] = ScuffleRoomData::APPLY_RESULT_STATUS_PASS;
            $updateData[$targetKey] = json_encode($data);
            $scuffleRoomModel->updateScuffleRoom($scuffleRoomData[ScuffleRoomData::ROOM_ID], $updateData);
            //通知车辆变化
            $scuffleRoomModel->broadcastPlayerCarChange($player, array_keys($scuffleRoomData), $playerId);
            $scuffleRoomModel->broadcastPlayerCarChange($applyPlayer, array_keys($scuffleRoomData), $applyPlayerId);
            return ClientErrorCode::CLIENT_SUCCESS;
        }
        //修改申请信息
        $key = $applyPlayerId ."#". ScuffleRoomData::APPLY_KEY;
        $data = json_decode($scuffleRoomData[$key], true);
        $data[ScuffleRoomData::APPLY_STATUS] = ScuffleRoomData::APPLY_STATUS_OVER;
        $data[$playerId] = ScuffleRoomData::APPLY_RESULT_STATUS_REFUSE;
        $updateData = array(
            $key => json_encode($data)
        );
        $targetKey = $playerId . "#". ScuffleRoomData::APPLY_KEY;
        $data = json_decode($scuffleRoomData[$targetKey], true);
        $data[ScuffleRoomData::APPLY_STATUS] = ScuffleRoomData::APPLY_STATUS_OVER;
        $data[$applyPlayerId] = ScuffleRoomData::APPLY_RESULT_STATUS_REFUSE;
        $updateData[$targetKey] = json_encode($data);
        $scuffleRoomModel->updateScuffleRoom($scuffleRoomData[ScuffleRoomData::ROOM_ID], $updateData);
        //通知换车结果
        $this->sendReplaceCarResultToApplyPlayer($option, $applyPlayerId, $playerId);
        return ClientErrorCode::CLIENT_SUCCESS;
    }

    //取消换车请求
    public function cancelReplaceCar(int $targetPlayerId, int $playerId): int
    {
        //检查对方id
        $scuffleRoomData = $this->getScuffleRoomByJoinId();
        if (empty($scuffleRoomData)) {
            //房间错误
            LogMark::getInstance()->markDebug(
                "[ScuffleLogic] search scuffle room error"
            );
            return ClientErrorCode::SCUFFLE_ROOM_NOT_FOUND;
        }
        //检查准备时间
        $readyTime = $this->getTerm(
            TemplateDefine::TYPE_CONST,
            TemplateConst::Const_Scuffle_Ready_Time,
            TemplateConst::ConstNum);
        if (Utils::getServerTimestamp() > $scuffleRoomData[ScuffleRoomData::CREATE_TIME] + $readyTime) {
            return ClientErrorCode::SCUFFLE_ROOM_OVER_READY_TIME;
        }
        if (!isset($scuffleRoomData[$targetPlayerId])) {
            return ClientErrorCode::SCUFFLE_ROOM_PLAYER_NOT_FOUND;
        }
        if ($targetPlayerId == $playerId) {
            return ClientErrorCode::SCUFFLE_ROOM_TARGET_PLAYER_ERROR;
        }
        //修改申请信息
        $key = $playerId ."#". ScuffleRoomData::APPLY_KEY;
        $data = json_decode($scuffleRoomData[$key], true);
        $data[ScuffleRoomData::APPLY_STATUS] = ScuffleRoomData::APPLY_STATUS_OVER;
        $data[$targetPlayerId] = ScuffleRoomData::APPLY_STATUS_OVER;
        $updateData = array(
            $key => json_encode($data)
        );
        $targetKey = $targetPlayerId . "#". ScuffleRoomData::APPLY_KEY;
        $data = json_decode($scuffleRoomData[$targetKey], true);
        $data[ScuffleRoomData::APPLY_STATUS] = ScuffleRoomData::APPLY_STATUS_OVER;
        $data[$playerId] = ScuffleRoomData::APPLY_STATUS_OVER;
        $updateData[$targetKey] = json_encode($data);
        /**
         * @var ScuffleRoomModel $scuffleRoomModel
         */
        $scuffleRoomModel = ModelManager::getInstance()->getModel(ModelTypeDefine::ROOM_SCUFFLE);
        $scuffleRoomModel->updateScuffleRoom($scuffleRoomData[ScuffleRoomData::ROOM_ID], $updateData);
        //通知对方取消
        if (!$this->checkIsAIPlayer($targetPlayerId)) {
            $cancelMessage = new GCCancelReplaceCarApply();
            $cancelMessage->setApplyPlayerId($playerId);
            $this->addPacket(PacketId::GC_CancelReplaceCarApply, $cancelMessage, $targetPlayerId);
        }
        return ClientErrorCode::CLIENT_SUCCESS;
    }

    private function sendReplaceCarResultToApplyPlayer(bool $option, int $applyPlayerId, int $playerId)
    {
        $message = new GCScuffleReplaceCarResult();
        $message->setOption($option);
        $message->setOptionPlayerId($playerId);
        $this->addPacket(PacketId::GC_ScuffleReplaceCarResult, $message, $applyPlayerId);
    }

    private function getScuffleRoomByJoinId(): ?array
    {
        /**
         * @var ScuffleRoomModel $scuffleRoomModel
         */
        $scuffleRoomModel = ModelManager::getInstance()->getModel(ModelTypeDefine::ROOM_SCUFFLE);
        return $scuffleRoomModel->getScuffleRoomDataByJoinId();
    }

    //增加车到公共车池
    private function addCarToPublicPool(int $carId, array &$publicPool)
    {
        $idx = $publicPool[ScuffleRoomData::INDEX];
        $publicPool[$idx][ScuffleRoomData::CAR_ID] = $carId;
        //新加入的车 有CD
        $cdTime = $this->getTerm(
            TemplateDefine::TYPE_CONST,
            TemplateConst::Const_Scuffle_Public_Pool_CD,
            TemplateConst::ConstNum);
        $publicCarPool[$idx][ScuffleRoomData::POOL_CD] = Utils::getServerTimestamp() + $cdTime;
        ++$publicPool[ScuffleRoomData::INDEX];
    }

    //更新玩家车信息
    //TODO:自己有的车 替换?
    private function updatePlayerCarInfo(PlayerInfo $playerInfo, int $carId)
    {
        $playerInfo->setCarTplId($carId);
        $playerInfo->setExteriorRefit("[]");
        $playerInfo->setProficiencyLv(1);
        $playerInfo->setProficiency(0);
    }

    //删除创建过期的房间
    public function delOverTimeScuffleRoom()
    {
        /**
         * @var ScuffleRoomModel $scuffleRoomModel
         */
        $scuffleRoomModel = ModelManager::getInstance()->getModel(ModelTypeDefine::ROOM_SCUFFLE);
        $scuffleRoomModel->dealOverTimeScuffleRoom();
    }
}
