<?php

/**
 * pvp结算相关
 */

namespace Game\Logic\Pvp;

use Framework\Log\LogMark;
use Framework\MVC\ModelManager;
use Game\Constant\ConstTemplate\TemplateCar;
use Game\Constant\ConstTemplate\TemplateCompetitionMode;
use Game\Constant\ConstTemplate\TemplateConst;
use Game\Constant\GameConstantDefine;
use Game\Constant\GameErrorCode;
use Game\Constant\ModelTypeDefine;
use Game\Constant\TemplateDefine;
use Game\Data\AccountData;
use Game\Data\RaceResultData;
use Game\Logic\GenerateAiLogic;
use Game\Logic\MapStatisticsLogic;
use Game\Model\AccountModel;

trait PvpSettlementLogic
{
    use MapStatisticsLogic;
    use GenerateAiLogic;

    //整理并结算pvp信息
    //更新: 连胜次数 结算参数破记录
    public function tidySettlementParams(array &$playerList, int $matchType, int $mapId): array
    {
        //获取配置
        $this->constConfigData = $this->getTable(TemplateDefine::TYPE_CONST);
        LogMark::getInstance()->markDebug(
            "[PVPFlowLog][PvpSettlementLogic] start tidySettlementParams",
            $playerList
        );
        if (in_array($matchType, GameConstantDefine::TEAM_MATCH_TYPE)) {
            return $this->tidySettlementParamsTeam($playerList, $matchType, $mapId);
        }
        //整理单人模式
        return $this->tidySettlementParamsSingle($playerList, $matchType, $mapId);
    }


    //整理单人模式
    //单人模式 没有mvp和徽章
    public function tidySettlementParamsSingle(array &$playerList, int $matchType, int $mapId): array
    {
        $breakingRecordInfo = array();  //破记录信息 playerId=>info
        foreach($playerList as $playerId => $raceResult) {
            /**
             * @var RaceResultData $raceResult
             */
            if ($raceResult->_rank <= 3) {
                $raceResult->_isWin = true;
            }
            //更新连胜次数
            $continuityWinNum = $this->updateContinuityWin($raceResult->_playerId, $matchType, $raceResult->_isWin);
            $raceResult->continuityWinNum = $continuityWinNum;
            //破记录数据
            $breakingRecordInfo[$playerId] = $this->updateMapStatistics(
                $playerId,
                $matchType,
                $raceResult->_carId,
                $mapId,
                $raceResult->parameter,
                $continuityWinNum
            );
        }
        return $breakingRecordInfo;
    }

    //整理组队模式
    public function tidySettlementParamsTeam(array &$playerList, int $matchType, int $mapId): array
    {
        $breakingRecordInfo = array();  //破记录信息 playerId=>info
        //徽章
        $iconList = array(
            "helpIcon" => array(),
            "jamIcon" => array(),
            "raceIcon" => array()
        );
        //组队信息
        $teamRank = array(  //groupId =>rank
            1 => array(),
            2 => array()
        );
        $rankPlayer = array();
        foreach($playerList as $playerId => $raceResult) {
            /**
             * @var RaceResultData $raceResult
             */
            //计算徽章归属
            $this->tidyIconData($raceResult, $iconList);
            //整理队伍胜利信息
            $teamRank[$raceResult->_groupId][] = $raceResult->_rank;
            if (isset($rankPlayer[$raceResult->_rank])) {
                //客户端名次相同bug检查--名次相同,后来的占用此名次,相同名次的查找判断胜负时,被占用的判负
                LogMark::getInstance()->markError(
                    GameErrorCode::MATCH_TEAM_RANK_SAME_ERROR,
                    "[PVPFlowLog][PvpSettlementLogic] pvp Team player Rank error,same rank",
                    $playerList
                );
            }
            $rankPlayer[$raceResult->_rank] = $raceResult->_playerId;
        }
        //徽章归属
        $this->markIconPlayer($iconList, $playerList);
        //队伍对位胜利检查
        [$playerIsWin, $winnerGroupId] = $this->setTeamWinner($teamRank, $rankPlayer);
        //计算mvp和svp
        $mvpPlayerId = 0;
        $mvpPlayerScore = 0;
        $svpPlayerId = 0;
        $svpPlayerScore = 0;
        foreach($playerList as $playerId => $raceResult) {
            /**
             * @var RaceResultData $raceResult
             */
            $mvpScore =  $this->getMvpScore($raceResult, $matchType, $playerIsWin);
            $raceResult->mvpScore = $mvpScore;
            if ($raceResult->_groupId == $winnerGroupId) {
                //设置组队胜利
                $raceResult->_teamWin = true;
                if ($mvpPlayerScore == 0) {
                    $mvpPlayerScore = $mvpScore;
                    $mvpPlayerId = $raceResult->_playerId;
                }
                if ($mvpScore > $mvpPlayerScore) {
                    $mvpPlayerScore = $mvpScore;
                    $mvpPlayerId = $raceResult->_playerId;
                }
            } else {
                if ($svpPlayerScore == 0) {
                    $svpPlayerScore = $mvpScore;
                    $svpPlayerId = $raceResult->_playerId;
                }
                if ($mvpScore > $mvpPlayerScore) {
                    $svpPlayerScore = $mvpScore;
                    $svpPlayerId = $raceResult->_playerId;
                }
            }
            $raceResult->_isWin = $playerIsWin[$playerId];
            //更新连胜次数
            $continuityWinNum = $this->updateContinuityWin($raceResult->_playerId, $matchType, $raceResult->_isWin);
            $raceResult->continuityWinNum = $continuityWinNum;
            //破记录数据
            $breakingRecordInfo[$playerId] = $this->updateMapStatistics(
                $playerId,
                $matchType,
                $raceResult->_carId,
                $mapId,
                $raceResult->parameter,
                $continuityWinNum
            );
        }
        $playerList[$mvpPlayerId]->_mvpIcon = true;
        $playerList[$svpPlayerId]->_svp = true;
        return $breakingRecordInfo;
    }

    //整理徽章数据,方便计算徽章归属
    private function tidyIconData(RaceResultData $raceResult, array &$iconList)
    {
        if ($raceResult->_helpNum > 0) {
            $iconList["helpIcon"][$raceResult->_playerId] = (int)($raceResult->_helpNum . abs($raceResult->_rank - 7));
        }
        if ($raceResult->_jamNum > 0) {
            $iconList["jamIcon"][$raceResult->_playerId] = (int)($raceResult->_jamNum . abs($raceResult->_rank - 7));
        }
        //竞速徽章 检查第一名车是否是竞速车
        if ($raceResult->_rank == 1) {
            $iconList["raceIcon"][0] = $raceResult->_playerId;
            $iconList["raceIcon"][1] = $raceResult->_carId;
        }
    }

    //计算是否获得徽章
    //干扰位->干扰徽章 干扰次数最多,数量相同时,按排名算
    //辅助位->辅助徽章 辅助次数最多,数量相同时,按排名算,个人赛没有
    //竞速位->竞速徽章 第一名获得
    private function markIconPlayer(array $iconList, array $playerList)
    {
        //竞速徽章
        if (!empty($iconList["raceIcon"])) {
            $pid = $iconList["raceIcon"][0];
            $carTplId = $iconList["raceIcon"][1];
            $carConfigData = $this->getTitle(TemplateDefine::TYPE_CAR, $carTplId);
            $carPositioning = $carConfigData[TemplateCar::Positioning];
            if ($carPositioning == TemplateCar::Positioning_Jam) {
                $playerList[$pid]->_raceIcon = true;
            }
        }
        //辅助徽章
        if (!empty($iconList["helpIcon"])) {
            $helpArr = $iconList["helpIcon"];
            arsort($helpArr);
            $playerList[array_keys($helpArr)[0]]->_helpIcon = true;
        }
        //干扰徽章
        if (!empty($iconList["jamIcon"])) {
            $jamArr = $iconList["jamIcon"];
            arsort($jamArr);
            $playerList[array_keys($jamArr)[0]]->_jamIcon = true;
        }
    }

    //计算mvp分数
    //公式:排名基础分+冲线得分+（辅助次数or干扰次数）*系数1+徽章数*系数2+胜败基础分
    private function getMvpScore(RaceResultData $raceResult, int $matchType, array $playerIsWin = array()): int
    {
        // 排名基础分
        $rankScore = $this->getConstConfigValue(TemplateConst::Const_MVP_Rank[$raceResult->_rank -1]);
        // 冲线分
        $compScore = 0;
        if ($raceResult->_costTime > 0) {
            $compScore = $this->getConstConfigValue(TemplateConst::Const_MVP_Comp);
        }
        //辅助次数or干扰次数）*系数1
        $score1 = ($raceResult->_helpNum + $raceResult->_jamNum) * $this->getConstConfigValue(TemplateConst::Const_MVP_Arg1);
        //徽章数*系数2
        $score2 = 0;
        if ($raceResult->_raceIcon || $raceResult->_jamIcon || $raceResult->_helpIcon) {
            $score2 = 1 * $this->getConstConfigValue(TemplateConst::Const_MVP_Arg2);
        }
        //胜败基础分
        if (in_array($matchType, GameConstantDefine::TEAM_MATCH_TYPE)) {
            //团队赛 检查对位胜利
            if ($playerIsWin[$raceResult->_playerId]) {
                $wfBaseScore = $this->getConstConfigValue(TemplateConst::Const_MVP_Base_Win);
            } else {
                $wfBaseScore = $this->getConstConfigValue(TemplateConst::Const_MVP_Base_Fail);
            }
        } else {
            //个人赛
            if ($raceResult->_rank <= 3) {
                $wfBaseScore = $this->getConstConfigValue(TemplateConst::Const_MVP_Base_Win);
            } else {
                $wfBaseScore = $this->getConstConfigValue(TemplateConst::Const_MVP_Base_Fail);
            }
        }
        return $rankScore + $compScore + $score1 + $score2 + $wfBaseScore;
    }

    //注意返回值:蓝图和碎片掉落概率为float 其他为int
    private function getConstConfigValue(int $id)
    {
        if (!isset($this->constConfigData[$id])) {
            LogMark::getInstance()->markWarn(
                GameErrorCode::TEMPLATE_ID_NOT_FOUND,
                "[MatchSettlementLogic] tpl table not found",
                array(
                    "TemplateTable" => TemplateDefine::TYPE_CONST,
                    "id" => $id
                )
            );
            return 0;
        }
        return $this->constConfigData[$id][TemplateConst::ConstNum];
    }

    //比赛结算道具--蓝图和碎片 获胜才有
    private function getReward(array &$reward, int $carId)
    {
        if ($this->isWin) {
            $carConfigData = $this->getTitle(TemplateDefine::TYPE_CAR, $carId);
            $rewardBoosters = $carConfigData[TemplateCar::Boosters];    //碎片id;蓝图id
            //蓝图
            $bluePrintRate = $this->getConstConfigValue(TemplateConst::Const_Match_Settlement_BluePrint_Rate);
            $t = lcg_value();
            if (isset($rewardBoosters[0]) && $bluePrintRate >= $t) {
                $itemId = $rewardBoosters[0];
                $num = $this->getConstConfigValue(TemplateConst::Const_Match_Settlement_BluePrint_Num);
                isset($reward[$itemId]) ? $reward[$itemId] += $num : $reward[$itemId] = $num;
            }
            //碎片
            $chipRate = $this->getConstConfigValue(TemplateConst::Const_Match_Settlement_Chip_Rate);
            $t = lcg_value();
            if (isset($rewardBoosters[1]) && $chipRate >= $t) {
                $itemId = $rewardBoosters[1];
                $num = $this->getConstConfigValue(TemplateConst::Const_Match_Settlement_Chip_Num);
                isset($reward[$itemId]) ? $reward[$itemId] += $num : $reward[$itemId] = $num;
            }
        }
    }

    // 模式结算道具
    private function getModeReward(array &$modeReword, int $modeType) {
        $modeConfig = $this->getTitle(TemplateDefine::TYPE_COMPETITION_MODE, $modeType);
        if (is_null($modeConfig)) {
            return;
        }
        if ($this->isWin) {
            $reward = $modeConfig[TemplateCompetitionMode::VictoryRewardItem];
        } else {
            $reward = $modeConfig[TemplateCompetitionMode::FailRewardItem];
        }
        foreach ($reward as $data) {
            if ($data[TemplateCompetitionMode::REWARD_RATIO] == 0) {
                continue;
            }
            if ($data[TemplateCompetitionMode::REWARD_RATIO] == 1) {
                //必得
                isset($modeReword[$data[TemplateCompetitionMode::REWARD_ID]]) ?
                    $modeReword[$data[TemplateCompetitionMode::REWARD_ID]] += $data[TemplateCompetitionMode::REWARD_NUM] :
                    $modeReword[$data[TemplateCompetitionMode::REWARD_ID]] = $data[TemplateCompetitionMode::REWARD_NUM];
            } else {
                $t = lcg_value();
                if($t >= $data[TemplateCompetitionMode::REWARD_RATIO]) {
                    isset($modeReword[$data[TemplateCompetitionMode::REWARD_ID]]) ?
                        $modeReword[$data[TemplateCompetitionMode::REWARD_ID]] += $data[TemplateCompetitionMode::REWARD_NUM] :
                        $modeReword[$data[TemplateCompetitionMode::REWARD_ID]] = $data[TemplateCompetitionMode::REWARD_NUM];
                }
            }
        }
    }

    //车辆熟练度 公式：熟练度=定位基数+排名分值+胜败加成
    private function getCarProficiency(RaceResultData $raceResult, bool $isWin): int
    {
        $base = 0;
        switch ($this->carPositioning) {
            case TemplateCar::Positioning_Race:
                //竞速位
                $base = $this->getConstConfigValue(TemplateConst::Const_Prof_Base_Race);
                $this->proficiencyArray[] = TemplateConst::Const_Prof_Base_Race;
                break;
            case TemplateCar::Positioning_Jam:
                //干扰位
                $base = $this->getConstConfigValue(TemplateConst::Const_Prof_Base_Jam);
                $this->proficiencyArray[] = TemplateConst::Const_Prof_Base_Jam;
                break;
            case TemplateCar::Positioning_Help:
                //辅助位
                $base = $this->getConstConfigValue(TemplateConst::Const_Prof_Base_Help);
                $this->proficiencyArray[] = TemplateConst::Const_Prof_Base_Help;
                break;
        }
        $rankScore = $this->getConstConfigValue(TemplateConst::Const_Prof_Rank[$raceResult->_rank -1]);
        $this->proficiencyArray[] = TemplateConst::Const_Prof_Rank[$raceResult->_rank -1];
        //胜负计算,个人赛为前三胜利,团队赛为队伍胜利
        if ($isWin) {
            $wfScore = $this->getConstConfigValue(TemplateConst::Const_Prof_Win);
            $this->proficiencyArray[] = TemplateConst::Const_Prof_Win;
        } else {
            $wfScore = $this->getConstConfigValue(TemplateConst::Const_Prof_Fail);
            $this->proficiencyArray[] = TemplateConst::Const_Prof_Fail;
        }
        return $base + $rankScore + $wfScore;
    }

    private function getAccountLvExp(bool $isWin, $matchType): int
    {
        //检查比赛模式是否加熟练度
        if ($matchType > 0) {
            $config = $this->getTitle(TemplateDefine::TYPE_COMPETITION_MODE, $matchType);
            if (is_null($config)) {
                return 0;
            }
            if ($config[TemplateCompetitionMode::WhetherExp] == 0) {
                return 0;
            }
        }

        $base = $this->getConstConfigValue(TemplateConst::Const_Exp_Base);
        $add = $this->getConstConfigValue(TemplateConst::Const_Exp_Add);
        $level = $this->getAccountProperty($this->playerId, AccountData::DB_LEVEL);
        if($isWin) {
            // 胜利获得经验=INT(（基础经验+等级*增长系数)*胜利系数/100)
            $win = $this->getConstConfigValue(TemplateConst::Const_Exp_Win);
            $score = (int)(($base + $level * $add) * $win / 100);
        } else {
            // 失败获得经验=INT(（基础经验+等级*增长系数)*失败系数/100)
            $fail = $this->getConstConfigValue(TemplateConst::Const_Exp_Fail);
            $score = (int)(($base + $level * $add) * $fail / 100);
        }
        return $score;
    }

    //车辆评分 仅排位赛结算 评分公式=车辆等级*系数1+车辆熟练度*系数2+MVP评分
    private function getCarScore(RaceResultData $raceResult, int $carProficiency): int
    {
        $car = $this->searchCarDataByCarID($raceResult->_carId);
        if (is_null($car)) {
            return 0;
        }
        $levelScore = $car->level * $this->getConstConfigValue(TemplateConst::Const_Car_Score_Arg1);
        $profScore = $carProficiency * $this->getConstConfigValue(TemplateConst::Const_Car_Score_Arg2);
        return $levelScore + $profScore + $raceResult->mvpScore;
    }

    //检查对位胜利
    //$teamRank groupId=>[rank,..]
    //$rankPlayer rank->playerId
    private function setTeamWinner(array $teamRank, array $rankPlayer): array
    {
        $playerIsWin = array(); //玩家对位胜利
        $teamWinNum = array(    //
            1 => 0,
            2 => 0,
        );

        //队伍名次排序
        sort($teamRank[1]);
        sort($teamRank[2]);
        for ($i = 0; $i <= 2; $i++) {
            if (isset($teamRank[1][$i], $teamRank[2][$i])) {
                if ($teamRank[1][$i] < $teamRank[2][$i]) {
                    //1队胜
                    $playerIsWin[$rankPlayer[$teamRank[1][$i]]] = true;
                    $playerIsWin[$rankPlayer[$teamRank[2][$i]]] = false;
                    ++$teamWinNum[1];
                } else {
                    //2队胜
                    $playerIsWin[$rankPlayer[$teamRank[1][$i]]] = false;
                    $playerIsWin[$rankPlayer[$teamRank[2][$i]]] = true;
                    ++$teamWinNum[2];
                }
            }
        }
        $winnerGroupId = $teamWinNum[1] > $teamWinNum[2] ? 1 : 2;
        return [$playerIsWin, $winnerGroupId];
    }

    //更新连胜次数,限练习赛,排位赛
    private function updateContinuityWin(int $playerId, int $matchType, bool $isWin): int
    {
        if ($this->checkIsAIPlayer($playerId)) {
            return 0;
        }
        switch ($matchType)
        {
            case GameConstantDefine::MATCH_MODE_SINGLE_PRACTISE:
            case GameConstantDefine::MATCH_MODE_TEAM_PRACTISE:
            case GameConstantDefine::MATCH_MODE_SINGLE_PAI_WEI:
            case GameConstantDefine::MATCH_MODE_TEAM_PAI_WEI:
                /**
                 * @var AccountModel $accountModel
                 */
                $accountModel = ModelManager::getInstance()->getModel(ModelTypeDefine::ACCOUNT);
                $accountModel->setPlayerId($playerId);
                if ($isWin) {
                    //增加连胜次数
                    return $accountModel->increaseAccountValue(AccountData::DB_CONTINUITY_WIN, 1);
                }
                //失败,重置连胜次数
                $accountModel->saveAccount(
                    array(
                        AccountData::DB_CONTINUITY_WIN => 0
                    )
                );
                return 0;
        }
        return 0;
    }
}
