<?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\TemplateChallengeTask;
use Game\Constant\ConstTemplate\TemplateChallengeTime;
use Game\Constant\EventTypeDefine;
use Game\Constant\GameConstantDefine;
use Game\Constant\ModelTypeDefine;
use Game\Constant\TemplateDefine;
use Game\Data\Activity\MapChallengeData;
use Game\Data\PvpPacket\PvpMsgData;
use Game\Logic\AccountLogic;
use Game\Logic\CarLogic;
use Game\Logic\CommonConstLogic;
use Game\Logic\ItemLogic;
use Game\Logic\RankLogic;
use Game\Model\Activity\MapChallengeModel;
use Game\Model\Car\CarModel;
use Game\Model\Rank\RankModel;
use Game\Protobuf\MapChallengeMapInfo;
use Game\Protobuf\MatchOperation;
use Game\Protobuf\PlayerMark;
use Game\Protobuf\TaleTarget;
use Game\Data\AccountData;

trait MapChallengeLogic
{
    use CommonConstLogic;
    use CarLogic;
    use ItemLogic;
    use RankLogic;
    use AccountLogic;

    //获取活动状态
    public function getMapChallengeStatus(): int
    {
        $result = $this->getCommonConstData();
        return isset($result[GameConstantDefine::COMMON_KEY_ACTIVITY_MAP_CHALLENGE_STATUS]) ?
            (int)$result[GameConstantDefine::COMMON_KEY_ACTIVITY_MAP_CHALLENGE_STATUS] :
            ActivityDefine::ACTIVITY_STATUS_UNOPENED;
    }

    //检查活动是否开启--进入地图,结算时检查使用
    public function checkMapChallengeCanEnter(int $mapId): int
    {
        $status = $this->getMapChallengeStatus();
        if ($status == ActivityDefine::ACTIVITY_STATUS_UNOPENED) {
            return ClientErrorCode::MAP_CHALLENGE_NOT_OPEN;
        }
        if ($status == ActivityDefine::ACTIVITY_STATUS_CLOSE) {
            return ClientErrorCode::MAP_CHALLENGE_CLOSED;
        }
        $result = $this->getCommonConstData();
        $activityId = $result[GameConstantDefine::COMMON_KEY_ACTIVITY_MAP_CHALLENGE];
        $openMap = $result[GameConstantDefine::COMMON_KEY_ACTIVITY_MAP_CHALLENGE_MAP];
        $openMapList = json_decode($openMap, true);
        if (!in_array($mapId, $openMapList)) {
            return ClientErrorCode::MAP_CHALLENGE_MAP_NOT_OPEN;
        }
        return ClientErrorCode::CLIENT_SUCCESS;
    }

    //获取活动地图--检查活动开启后使用
    public function getMapChallengeInfo(): array
    {
        $result = $this->getCommonConstData();
        $activityId = $result[GameConstantDefine::COMMON_KEY_ACTIVITY_MAP_CHALLENGE];
        $openMap = $result[GameConstantDefine::COMMON_KEY_ACTIVITY_MAP_CHALLENGE_MAP];
        $openMapList = json_decode($openMap, true);
        /**
         * @var MapChallengeModel $mapChallengeModel
         */
        $mapChallengeModel = ModelManager::getInstance()->getModel(ModelTypeDefine::ACTIVITY_MAP_CHALLENGE);
        $mapChallengeData = $mapChallengeModel->getMapChallengeData($activityId);
        $mapList = array();
        foreach ($openMapList as $mapId) {
            $mapChallengeInfo = new MapChallengeMapInfo();
            [
                $dbKeyMapBestTime,
                $dbKeyMapCompleteTaskNum,
                $dbKeyMapAllCompleteFlag,
                $dbKeyMapCanGetRewardId,
                $dbKeyMapAlreadyGetRewardId
            ] = MapChallengeData::getMapKey($mapId);
            $mapData = $mapChallengeModel->getMapChallengeMapData($activityId, $mapId);
            $mapChallengeInfo->setMapId($mapId)
                ->setBestTime($mapData[$dbKeyMapBestTime])
                ->setCompleteNum($mapData[$dbKeyMapCompleteTaskNum])
                ->setCompleteTaskId($mapData[$dbKeyMapCanGetRewardId])
                ->setGetTaskId($mapData[$dbKeyMapAlreadyGetRewardId]);
            $mapList[] = $mapChallengeInfo;
        }
        return [$activityId, $mapList, $mapChallengeData[MapChallengeData::REWARD_STATUS]];
    }

    //进入地图挑战检查
    public function enterMapChallengeCheck(int $mapId): int
    {
        $code = $this->checkMapChallengeCanEnter($mapId);
        if ($code != ClientErrorCode::CLIENT_SUCCESS) {
            return $code;
        }
        //检查车是否过期
        $drivingCarId = $this->getAccountAttribute(AccountData::DB_DEFAULT_CAT_TPL);
        $car = $this->searchCarDataByCarID($drivingCarId);
        if (is_null($car)) {
            LogMark::getInstance()->markDebug(
                "[MapChallengeLogic] not found driving car",
                array(
                    "carId" => $drivingCarId
                )
            );
            return ClientErrorCode::CAR_IS_EXPIRE;
        }
        if ($car->expire != CarModel::CAR_EXPIRE_NORMAL && Utils::getServerTimestamp() >= $car->expire) {
            return ClientErrorCode::CAR_IS_EXPIRE;
        }
        //检查成功
        //记录车辆使用次数和状态
        $this->recordCarUseNum($drivingCarId);
        $this->upRoleStatus(GameConstantDefine::PLAYER_STATUS_GAMING, $this->playerId);
        return ClientErrorCode::CLIENT_SUCCESS;
    }

    //地图挑战结算--只检查时间
    public function mapChallengeSettlement(int $mapId,
        PlayerMark $player,
        TaleTarget $taleTarget,
        MatchOperation $matchOperation): MapChallengeMapInfo
    {
        $result = $this->getCommonConstData();
        $activityId = $result[GameConstantDefine::COMMON_KEY_ACTIVITY_MAP_CHALLENGE];
        $openMap = $result[GameConstantDefine::COMMON_KEY_ACTIVITY_MAP_CHALLENGE_MAP];
        $openMapList = json_decode($openMap, true);
        /**
         * @var MapChallengeModel $mapChallengeModel
         */
        $mapChallengeModel = ModelManager::getInstance()->getModel(ModelTypeDefine::ACTIVITY_MAP_CHALLENGE);
        //获取地图数据
        $mapChallengeData = $mapChallengeModel->getMapChallengeData($activityId);
        [
            $dbKeyMapBestTime,
            $dbKeyMapCompleteTaskNum,
            $dbKeyMapAllCompleteFlag,
            $dbKeyMapCanGetRewardId,
            $dbKeyMapAlreadyGetRewardId
        ] = MapChallengeData::getMapKey($mapId);
        $mapData = $mapChallengeModel->getMapChallengeMapData($activityId, $mapId);
        $mapChallengeInfo = new MapChallengeMapInfo();
        $mapChallengeInfo->setMapId($mapId)
            ->setBestTime($mapData[$dbKeyMapBestTime])
            ->setCompleteNum($mapData[$dbKeyMapCompleteTaskNum])
            ->setCompleteTaskId($mapData[$dbKeyMapCanGetRewardId])
            ->setGetTaskId($mapData[$dbKeyMapAlreadyGetRewardId]);
        if ($player->getCostTime() == 0) {
            //比赛未完成,不更新数据
            return $mapChallengeInfo;
        }
        //地图配置
        $mapConfig = $this->getTitle(TemplateDefine::TYPE_CHALLENGE_TASK, $mapId);
        if (is_null($mapConfig)) {
            LogMark::getInstance()->markDebug(
                "[MapChallengeLogic] not found challenge map config",
                array(
                    "mapId" => $mapId
                )
            );
            return $mapChallengeInfo;
        }
        //触发任务--参与比赛
        $param = array(
            GameConstantDefine::EVENT_KEY_MATCH_MAP => $mapId,
            GameConstantDefine::EVENT_KEY_MATCH_TYPE => GameConstantDefine::MATCH_MODE_MPA_CHALLENGE,
            GameConstantDefine::EVENT_KEY_CAR_ID => 0,
        );
        $this->triggerEvent(EventTypeDefine::EVENT_TYPE_TASK_JOIN_MATCH, $param);
        $updateData = array();
        //检查是否已全部完成
        if ($mapData[$dbKeyMapAllCompleteFlag] == MapChallengeData::MAP_ALL_COMPLETE_FLAG_OVER) {
            //全部完成,只检查更新最佳时间
            if ($mapData[$dbKeyMapBestTime] > $player->getCostTime()) {
                $updateData[$dbKeyMapBestTime] = $player->getCostTime();
                //检查更新排行榜
                $this->checkUpdateRank($player->getCostTime(), $mapId);
                $mapChallengeInfo->setBestTime($player->getCostTime());
            }
            if (!empty($updateData)) {
                $mapChallengeModel->saveMapChallengeData($activityId, $updateData);
            }
            return $mapChallengeInfo;
        }
        //检查最佳时间
        $costTime = $player->getCostTime();
        $bestTime = $mapData[$dbKeyMapBestTime];
        if ($bestTime == 0) {
            $bestTime = $costTime;
            //检查更新排行榜
            $this->checkUpdateRank($bestTime, $mapId);
        }
        if ($costTime < $bestTime) {
            $bestTime = $costTime;
            //检查更新排行榜
            $this->checkUpdateRank($bestTime, $mapId);
        }
        $updateData[$dbKeyMapBestTime] = $bestTime;
        //检查完成进度
        $mapCanGetRewardId = $mapData[$dbKeyMapCanGetRewardId];
        foreach ($mapConfig as $id => $configData) {
            if ($mapCanGetRewardId >= $id) {
                continue;
            }
            //检查完成目标
            if ($costTime <= $configData[TemplateChallengeTask::Target]) {
                $mapCanGetRewardId = $id;
            }
        }
        $updateData[$dbKeyMapCanGetRewardId] = $mapCanGetRewardId;
        //检查完成数
        if ($mapCanGetRewardId == 0) {
            $completeNum = 0;
        } else {
            $completeNum = $mapCanGetRewardId - array_key_first($mapConfig) + 1;
        }
        $updateData[$dbKeyMapCompleteTaskNum] = $completeNum;
        //检查是否全部完成
        if ($completeNum == count($mapConfig)) {
            $updateData[$dbKeyMapAllCompleteFlag] = MapChallengeData::MAP_ALL_COMPLETE_FLAG_OVER;
            //检查大奖状态
            $updateData[MapChallengeData::REWARD_STATUS] = $this->checkActivityRewardStatus($activityId, $openMapList, $mapChallengeModel);
        }
        //保存
        $mapChallengeModel->saveMapChallengeData($activityId, $updateData);
        $mapChallengeInfo->setMapId($mapId)
            ->setBestTime($bestTime)
            ->setCompleteNum($completeNum)
            ->setCompleteTaskId($mapCanGetRewardId)
            ->setGetTaskId($mapData[$dbKeyMapAlreadyGetRewardId]);
        return $mapChallengeInfo;
    }

    //完成地图全部挑战后,检查大奖状态
    private function checkActivityRewardStatus(int $activityId, array $openMapList, MapChallengeModel $mapChallengeModel): int
    {
        $activityConfig = $this->getTitle(TemplateDefine::TYPE_CHALLENGE_TIME, $activityId);
        if (is_null($activityConfig)) {
            LogMark::getInstance()->markDebug(
                "[MapChallengeLogic] not found challenge Time config",
                array(
                    "Id" => $activityId
                )
            );
            return MapChallengeData::REWARD_STATUS_CAN_NOT_GET;
        }
        if (empty($activityConfig[TemplateChallengeTime::Reward])) {
            //没有配置奖励
            return MapChallengeData::REWARD_STATUS_CAN_NOT_GET;
        }
        if (count($activityConfig[TemplateChallengeTime::MapId]) != count($openMapList)) {
            //地图未全部开启,未完成全部挑战
            return MapChallengeData::REWARD_STATUS_CAN_NOT_GET;
        }
        $compNum = 1;
        foreach ($openMapList as $mapId) {
            [
                $dbKeyMapBestTime,
                $dbKeyMapCompleteTaskNum,
                $dbKeyMapAllCompleteFlag,
                $dbKeyMapCanGetRewardId,
                $dbKeyMapAlreadyGetRewardId
            ] = MapChallengeData::getMapKey($mapId);
            $mapData = $mapChallengeModel->getMapChallengeMapData($activityId, $mapId);
            $compNum += $mapData[$dbKeyMapAllCompleteFlag];
        }
        if ($compNum >= count($activityConfig[TemplateChallengeTime::MapId])) {
            //全部完成 可领取
            return MapChallengeData::REWARD_STATUS_CAN_GET;
        }
        return MapChallengeData::REWARD_STATUS_CAN_NOT_GET;
    }

    //检查更新排行榜
    public function checkUpdateRank(int $time, int $mapId)
    {
        $num = $this->changeRankMapEventPooled(RankModel::MAP_CHALLENGE, $time, $mapId);
        $this->changeRankScore(RankModel::MAP_CHALLENGE, $num, $mapId, true);
    }

    private function changeRankMapEventPooled($type, $score,int $mapID = 0)
    {
        $res = [];
        $seasonID = 0;
        if(in_array($type, RankModel::RANK_SEASON_TYPE)) {
            $seasonID = $this->getSeasonId();
            if($seasonID == 0) {
                return false;
            }
        }
        $value = $this->getSingleEventConditionValue(
            $this->getRankingKey($type, $seasonID, $mapID)
        );
        if($value == 0) {
            $this->addEventConditionValue($this->getRankingKey($type, $seasonID, $mapID), $score);
            $newScore = $score;
        } elseif ($value > $score){
            $this->addEventConditionValue($this->getRankingKey($type, $seasonID, $mapID), $score - $value);
            $newScore = $score;
        } else {
            $newScore = $value;
        }
        return $newScore;
    }

    //领取大奖
    public function getMapChallengeReward(): array
    {
        $result = $this->getCommonConstData();
        $activityId = $result[GameConstantDefine::COMMON_KEY_ACTIVITY_MAP_CHALLENGE];
        $activityConfig = $this->getTitle(TemplateDefine::TYPE_CHALLENGE_TIME, $activityId);
        if (is_null($activityConfig)) {
            LogMark::getInstance()->markDebug(
                "[MapChallengeLogic] not found challenge Time config",
                array(
                    "Id" => $activityId
                )
            );
            return [
                ClientErrorCode::MAP_CHALLENGE_REWARD_CAN_NOT_GET,
                MapChallengeData::REWARD_STATUS_CAN_NOT_GET
            ];
        }
        if (empty($activityConfig[TemplateChallengeTime::Reward])) {
            //没有配置奖励
            return [
                ClientErrorCode::MAP_CHALLENGE_REWARD_CAN_NOT_GET,
                MapChallengeData::REWARD_STATUS_CAN_NOT_GET
            ];
        }
        /**
         * @var MapChallengeModel $mapChallengeModel
         */
        $mapChallengeModel = ModelManager::getInstance()->getModel(ModelTypeDefine::ACTIVITY_MAP_CHALLENGE);
        $mapChallengeData = $mapChallengeModel->getMapChallengeData($activityId);
        if ($mapChallengeData[MapChallengeData::REWARD_STATUS] == MapChallengeData::REWARD_STATUS_CAN_NOT_GET) {
            return [
                ClientErrorCode::MAP_CHALLENGE_REWARD_CAN_NOT_GET,
                $mapChallengeData[MapChallengeData::REWARD_STATUS]
            ];
        }
        if ($mapChallengeData[MapChallengeData::REWARD_STATUS] == MapChallengeData::REWARD_STATUS_ALREADY_GET) {
            return [
                ClientErrorCode::MAP_CHALLENGE_REWARD_ALREADY_GET,
                $mapChallengeData[MapChallengeData::REWARD_STATUS]
            ];
        }
        //领取奖励
        $this->setLogAddItemSource(GameConstantDefine::ITEM_ADD_SOURCE_MAP_CHALLENGE_REWARD);
        $this->gainItemArr($activityConfig[TemplateChallengeTime::Reward]);

        $mapChallengeModel->saveMapChallengeData(
            $activityId,
            array(MapChallengeData::REWARD_STATUS => MapChallengeData::REWARD_STATUS_ALREADY_GET)
        );
        return [
            ClientErrorCode::CLIENT_SUCCESS,
            MapChallengeData::REWARD_STATUS_ALREADY_GET
        ];
    }

    //领取地图奖励
    public function getMapChallengeMapReward(int $mapId): array
    {
        $result = $this->getCommonConstData();
        $activityId = $result[GameConstantDefine::COMMON_KEY_ACTIVITY_MAP_CHALLENGE];
        $openMap = $result[GameConstantDefine::COMMON_KEY_ACTIVITY_MAP_CHALLENGE_MAP];
        $openMapList = json_decode($openMap, true);
        /**
         * @var MapChallengeModel $mapChallengeModel
         */
        $mapChallengeModel = ModelManager::getInstance()->getModel(ModelTypeDefine::ACTIVITY_MAP_CHALLENGE);
        //获取地图数据
        $mapChallengeData = $mapChallengeModel->getMapChallengeData($activityId);
        [
            $dbKeyMapBestTime,
            $dbKeyMapCompleteTaskNum,
            $dbKeyMapAllCompleteFlag,
            $dbKeyMapCanGetRewardId,
            $dbKeyMapAlreadyGetRewardId
        ] = MapChallengeData::getMapKey($mapId);
        $mapData = $mapChallengeModel->getMapChallengeMapData($activityId, $mapId);
        $mapChallengeInfo = new MapChallengeMapInfo();
        $mapChallengeInfo->setMapId($mapId)
            ->setBestTime($mapData[$dbKeyMapBestTime])
            ->setCompleteNum($mapData[$dbKeyMapCompleteTaskNum])
            ->setCompleteTaskId($mapData[$dbKeyMapCanGetRewardId])
            ->setGetTaskId($mapData[$dbKeyMapAlreadyGetRewardId]);
        if (!in_array($mapId, $openMapList)) {
            //地图未开启
            return [
                ClientErrorCode::MAP_CHALLENGE_MAP_NOT_OPEN,
                $mapChallengeInfo
            ];
        }
        //地图配置
        $mapConfig = $this->getTitle(TemplateDefine::TYPE_CHALLENGE_TASK, $mapId);
        if (is_null($mapConfig)) {
            LogMark::getInstance()->markDebug(
                "[MapChallengeLogic] not found challenge map config",
                array(
                    "mapId" => $mapId
                )
            );
            return [
                ClientErrorCode::MAP_CHALLENGE_MAP_NOT_OPEN,
                $mapChallengeInfo
            ];
        }
        $itemReward = array();
        //检查可领取奖励
        $mapCanGetRewardId = $mapData[$dbKeyMapCanGetRewardId];         //可领取的最大id
        $mapAlreadyGetRewardId = $mapData[$dbKeyMapAlreadyGetRewardId]; //已领取的最大id
        if ($mapCanGetRewardId == $mapAlreadyGetRewardId) {
            //没有可领取的
            return [
                ClientErrorCode::CLIENT_SUCCESS,
                $mapChallengeInfo
            ];
        }
        foreach ($mapConfig as $id => $configData) {
            if ($id > $mapCanGetRewardId) {
                break;
            }
            if ($mapAlreadyGetRewardId >= $id) {
                continue;
            }
            foreach ($configData[TemplateChallengeTask::Reward] as $rewardId => $num) {
                isset($itemReward[$rewardId]) ? $itemReward[$rewardId] += $num : $itemReward[$rewardId] = $num;
            }
        }
        $mapChallengeModel->saveMapChallengeData(
            $activityId,
            array($dbKeyMapAlreadyGetRewardId => $mapCanGetRewardId)
        );
        //发奖
        $this->setLogAddItemSource(GameConstantDefine::ITEM_ADD_SOURCE_MAP_CHALLENGE_REWARD);
        $this->gainItemArr($itemReward);

        $mapChallengeInfo->setGetTaskId($mapCanGetRewardId);
        return [
            ClientErrorCode::CLIENT_SUCCESS,
            $mapChallengeInfo
        ];
    }
}
