<?php

/**
 * 组队排位
 */

namespace Game\Model\Pvp\Mode;

use Framework\Log\LogMark;
use Framework\DB\Handler\PlayerDBHandler;
use Framework\Logic\PacketCacheLogic;
use Framework\Logic\TemplateHelp;
use Game\Config\GameConfig;
use Game\Constant\ClientErrorCode;
use Game\Constant\ConstTemplate\TemplateCar;
use Game\Constant\ConstTemplate\TemplateConst;
use Game\Constant\ConstTemplate\TemplateIntegral;
use Game\Constant\ConstTemplate\TemplateRankPosition;
use Game\Constant\ConstTemplate\TemplateSeasonRewardCondition;
use Game\Constant\EventTypeDefine;
use Game\Constant\GameConstantDefine;
use Game\Constant\GameErrorCode;
use Game\Constant\ModelTypeDefine;
use Game\Constant\TemplateDefine;
use Game\Data\PaiWei\PaiweiLevelData;
use Game\Data\PvpPacket\PvpMsgData;
use Game\Data\RaceResultData;
use Game\Data\RecordData;
use Game\Data\RoomData;
use Game\Logic\CarLogic;
use Game\Logic\ItemLogic;
use Game\Logic\PaiweiLevelLogic;
use Game\Logic\Pvp\PvpLogic;
use Game\Logic\Pvp\PvpMatchLogic;
use Game\Logic\Pvp\PvpSettlementLogic;
use Game\Method\Player\AddPlayerExp;
use Game\Model\Pvp\PvpBaseModel;
use Game\Model\RoomModel;
use Game\Protobuf\CarShow;
use Game\Protobuf\GCCancelMatch;
use Game\Protobuf\GCRaceResult;
use Game\Protobuf\GCStartMatching;
use Game\Protobuf\GMJoinMatch;
use Game\Protobuf\PacketId;
use Game\Protobuf\PlayerInfo;
use Game\Protobuf\GCPVPMatchingSuccess;
use Game\Protobuf\PlayerShow;
use Game\Protobuf\RewardItem;
use Game\Protobuf\RoomPlayers;
use Game\Protobuf\TeamRankingMatchParam;

class TeamRankingModel
{
    use PlayerDBHandler;
    use PaiweiLevelLogic;
    use TemplateHelp;
    use CarLogic;
    use ItemLogic;
    use PvpLogic;
    use PacketCacheLogic;
    use PvpMatchLogic;
    use PvpSettlementLogic;
    use AddPlayerExp;

    public int $playerId;

    private bool $isWin = false;            //对位胜负标志
    private int $carPositioning;            //车辆定位
    private ?array $constConfigData;        //配置表
    private array $mvpScoreDict = array();  //mvp分数信息 (playerId=>mvpScore)
    private int $joinId = 0;
    private ?array $paiweiConfigData;       //排位赛积分配置表
    private array $scoreArray = array();    //段位分获得id
    private array $proficiencyArray = array();  //熟练度获取详情

    private array $sendRaceResultList = array();
    private GCRaceResult $sendMessage;
    public GCStartMatching $startMatchingMsg;
    public GCCancelMatch   $cancelMatchMsg;

    public function __construct()
    {
        $this->startMatchingMsg = new GCStartMatching();
        $this->cancelMatchMsg = new GCCancelMatch();
    }

    public function setPlayerId($playerId)
    {
        $this->playerId = $playerId;
    }

    // 加入匹配
    public function sendJoinMatchPacket(int $joinID, RoomData $room, bool $isRand): bool {
        $playerID = $this->playerId;
        $serverID = GameConfig::getInstance()->SERVER_ID();
        $playerInfo = [];
        //生成匹配数据
        foreach($room->playerInfo as $id => $data) {
            $player = new RoomPlayers();
            $player->setPlayerID($id);
            $player->setPlayerShow($this->makePlayerShowString($id, $data));
            $player->setCarShow($this->makeCarShowString($id, $data, $room->mapID));
            $playerInfo[] = $player;
        }

        // 通过相应的protobuf 组装发送匹配数据
        $match = new GMJoinMatch();
        $match->setPlayerID($playerID);
        $match->setServerID($serverID);
        $match->setJoinID($joinID);
        $match->setMapID($room->mapID);
        $match->setMatchType($room->modeType);
        $match->setPlayer($playerInfo);
        //排位赛匹配参数
        $match->setMatchParam($this->getRankingMatchParam($room->playerInfo, $match));
        //发送匹配消息
        if($this->sendJoinMatchingPacket($match)) {
            //发送成功
            LogMark::getInstance()->markInfo(
                "[PVPFlowLog][2][TeamRankingModel]joinMatching success",
                (array)$room + ['joinID' => $joinID]
            );
            $this->joinRoomMsg(ClientErrorCode::CLIENT_SUCCESS);
            $this->addJoinRoomMsg($room->playerInfo);
            $room->setPlayType(RoomModel::ROOM_GAME_MATCH_OR_PLAY);
            if($isRand) {
                //随机地图房间 地图继续显示随机
                $room->mapID = PvpBaseModel::RandMapNum;
            }
            if(!$room->saveDB()) {
                LogMark::getInstance()->markError(
                    GameErrorCode::DATA_UPDATE_ERROR,
                    "[PVPFlowLog][TeamRankingModel] joinMatching change room play type fail",
                    (array)$room
                );
                return false;
            }
        } else {
            //发送失败
            LogMark::getInstance()->markError(
                GameErrorCode::DATA_UPDATE_ERROR,
                "[PVPFlowLog][TeamRankingModel]joinMatching fail",
                (array)$room
            );
            $this->joinRoomMsg(ClientErrorCode::PVP_JOIN_MATCH_ERROR);
            $this->joinRoomMsgSend();
            return false;
        }
        return true;
    }

    /**
     * 排位赛匹配特殊参数
     * @param array $roomPlayer
     * @param GMJoinMatch $match
     * @return string
     */
    private function getRankingMatchParam(array $roomPlayer, GMJoinMatch $match): string
    {
        //匹配保护机制--直接匹AI
        //1.当玩家段位为青铜4（最低段位）时，匹配ai对手。
        //2.当玩家段位为青铜3-黄金1时，玩家三连败时，下一场匹配ai对手。
        //3.当玩家段位为铂金-钻石时，玩家5连败后，下一场匹配ai对手。
        //个人赛：除了我都是ai  团队赛：友方真人，对手ai
        $ownerLv = 1;   //房主段位
        $joinTime = 0;
        $allAI = false;
        $rankingScore = array();    //排位分
        $positionList = array();
        $constConfig = $this->getTable(TemplateDefine::TYPE_CONST);
        foreach($roomPlayer as $pid => $data) {
            $rankingScore[] = $this->getRankingScore($pid);
            $paiWeiData = $this->getTargetPaiWeiLevel($pid);
            $positionList[$pid] = array(
                $paiWeiData->firstChoiceNum,
                $paiWeiData->score,
                json_decode($paiWeiData->positionOrder, true)
            );
            //查找房主
            if ($joinTime == 0) {
                $joinTime = $data[RoomData::JOIN_TIME];
                $ownerLv = $paiWeiData->levelId;
            }
            if ($joinTime < $data[RoomData::JOIN_TIME]) {
                $joinTime = $data[RoomData::JOIN_TIME];
                $ownerLv = $paiWeiData->levelId;
            }
            if ($paiWeiData->levelId == $constConfig[TemplateConst::Const_Ranking_AI_Min_Level][TemplateConst::ConstNum]) {
                $allAI = true;
            } elseif ($paiWeiData->levelId >= $constConfig[TemplateConst::Const_Ranking_AI_1_Min_Level][TemplateConst::ConstNum] &&
                $paiWeiData->levelId <= $constConfig[TemplateConst::Const_Ranking_AI_1_Max_Level][TemplateConst::ConstNum] &&
                $paiWeiData->record <= $constConfig[TemplateConst::Const_Ranking_AI_1_Lose_Num][TemplateConst::ConstNum]) {
                $allAI = true;
            } elseif ($paiWeiData->levelId >= $constConfig[TemplateConst::Const_Ranking_AI_2_Min_Level][TemplateConst::ConstNum] &&
                $paiWeiData->levelId <= $constConfig[TemplateConst::Const_Ranking_AI_2_Min_Level][TemplateConst::ConstNum] &&
                $paiWeiData->record <= $constConfig[TemplateConst::Const_Ranking_AI_2_Min_Level][TemplateConst::ConstNum]) {
                $allAI = true;
            }
        }
        //需要的真实敌人数量
        $needTargetPlayerNum = 3;
        if ($allAI) {
            $needTargetPlayerNum = 0;
        }
        //根据房主段位,查询匹配配置
        [$maxTime, $lvRange, $matchTimeProto] = $this->getRankingConfig($ownerLv);
        $matchParam = new TeamRankingMatchParam();
        $matchParam->setLevel($ownerLv);
        $matchParam->setLevelRange($lvRange);
        $matchParam->setScore($this->getAvgRankingScore($rankingScore));
        $matchParam->setMatchTimeScore($matchTimeProto);
        //计算位置选择
        $position = $this->markPositionOrder($positionList);
        LogMark::getInstance()->markDebug(
            "[TeamRankingModel] getRankingMatchParam position",
            $position
        );
        foreach ($position as $p => $value) {
            if ($value == 0) {
                continue;
            }
            $pos = $p + 1;
            if (count($positionList) == 1) {
                [$pid, $ratio] = explode("*", $value);
            } else {
                $pid = $value;
                $ratio = 0;
            }
            $key1 = "setPosition{$pos}PlayerId";
            $key2 = "setPosition{$pos}Ratio";
            $matchParam->$key1($pid);
            $matchParam->$key2($ratio);
        }
        $match->setMaxTime($maxTime);
        $match->setNeedPlayerNum(3 - count($roomPlayer));
        $match->setNeedTargetNum($needTargetPlayerNum);
        LogMark::getInstance()->markInfo(
            '[TeamRankingModel] getRankingMatchParam:'.$matchParam->serializeToJsonString(),
        );
        return base64_encode($matchParam->serializeToString());
    }

    //计算位置选择
    //$positionList[$pid] = array(
    //                $paiWeiData->firstChoiceNum,  // 首选场次
    //                $paiWeiData->score,           //积分
    //                json_decode($paiWeiData->positionOrder, true) //位置
    //            );
    //当玩家在当前分段积分为0时，默认选择首选位置，并且不开放其他位置。
    public function markPositionOrder(array $positionList): array
    {
        //根据人数计算
        if (count($positionList) == 1) {
            return $this->markPositionOrder1($positionList);
        }
        if (count($positionList) == 2) {
            return $this->markPositionOrder2($positionList);
        }
        return $this->markPositionOrder3($positionList);
    }


    //1人匹配位置计算--返回 [playerId*概率,..]
    private function markPositionOrder1(array $positionList): array
    {
        $tmp = array(
            0 => 0,
            1 => 0,
            2 => 0
        );
        $pid = array_key_first($positionList);
        $data = $positionList[$pid];
        if ($data[1] == 0) {
            //默认选择首选位
            $position = $data[2][0];
            $tmp[$position - 1] = $pid . "*100";
            return $tmp;
        }
        //根据场次算首选位
        $positionRatioList = $this->getTeamPositionConfigByNum($data[0]);
        foreach ($positionRatioList as $i => $ratio) {
            if ($ratio == 0) {
                $tmp[$data[2][$i - 1] -1] = 0;
            } else {
                $tmp[$data[2][$i - 1] -1] = $pid . "*{$ratio}";
            }
        }
        return $tmp;
    }

    //2人匹配位置计算--两个人排好顺序,缺少的位置为0
    private function markPositionOrder2(array $positionList): array
    {
        //按照 概率.位置 从大到小排序,选出位置
        $queue1 = array();
        $queue2 = array();
        $i = 1;
        foreach ($positionList as $pId => $positionData) {
            if ($positionData[1] == 0) {
                //默认选择首选位
                if ($i == 1) {
                    $queue1[] = 100;
                } else {
                    $queue2[] = 100;
                }
            } else {
                $position = $this->getTeamPositionConfigByNum($positionData[0]);
                foreach ($position as $p => $ratio) {
                    if ($i == 1) {
                        $queue1[] = $ratio;
                    } else {
                        $queue2[] = $ratio;
                    }
                }
            }
            $i++;
        }
        $tmp = array(
            0 => 0,
            1 => 0,
            2 => 0
        );
        //计算选择位置
        if ($queue1 == $queue2) {
            //选择一致 随机位置
            [$position1, $position2] = array_rand([1,2,3], 2);
            $tmp[$position1] = array_keys($positionList)[0];
            $tmp[$position2] = array_keys($positionList)[1];
            return $tmp;
        }
        //按顺序检查位置和概率
        if ($queue1[0] > $queue2[0]) {
            //首选位相同,玩家1概率大,选中
            $tmp[array_values($positionList)[0][2][0] - 1] = array_keys($positionList)[0];
            foreach (array_values($positionList)[1][2] as $p2Position) {
                if ($tmp[$p2Position - 1] == 0) {
                    $tmp[$p2Position - 1] = array_keys($positionList)[1];
                    break;
                }
            }
            return $tmp;
        }
        $tmp[array_values($positionList)[1][2][0] - 1] = array_keys($positionList)[1];
        foreach (array_values($positionList)[0][2] as $p2Position) {
            if ($tmp[$p2Position - 1] == 0) {
                $tmp[$p2Position - 1] = array_keys($positionList)[0];
                break;
            }
        }
        return $tmp;
    }

    //3人匹配位置计算--3人必定排好顺序
    private function markPositionOrder3(array $positionList): array
    {
        //按照 概率.位置 从大到小排序,选出位置
        $queue1 = array();
        $queue2 = array();
        $queue3 = array();
        $i = 1;
        foreach ($positionList as $pId => $positionData) {
            if ($positionData[1] == 0) {
                //默认选择首选位
                if ($i == 1) {
                    $queue1[] = 100;
                }
                if ($i == 2) {
                    $queue2[] =  100;
                }
                if ($i == 3) {
                    $queue3[] =  100;
                }
            } else {
                $position = $this->getTeamPositionConfigByNum($positionData[0]);
                foreach ($position as $p => $ratio) {
                    if ($i == 1) {
                        $queue1[] = $ratio;
                    }
                    if ($i == 2) {
                        $queue2[] = $ratio;
                    }
                    if ($i == 3) {
                        $queue3[] = $ratio;
                    }
                }
            }
            $i++;
        }
        $tmp = array(
            0 => 0,
            1 => 0,
            2 => 0
        );
        //计算选择位置
        if ($queue1 == $queue2 && $queue1 == $queue3) {
            //选择一致 随机位置
            $arr = array(0, 1, 2);
            shuffle($arr);
            $tmp[$arr[0]] = array_keys($positionList)[0];
            $tmp[$arr[1]] = array_keys($positionList)[1];
            $tmp[$arr[2]] = array_keys($positionList)[2];
            return $tmp;
        }
        $ratioArr = array(
            0 => $queue1[0],
            1 => $queue2[0],
            2 => $queue3[0]
        );
        arsort($ratioArr);
        $pList = array_keys($ratioArr); //玩家选位顺序
        [$playerIndex1, $playerIndex2, $playerIndex3] = $pList;
        $tmp[array_values($positionList)[$playerIndex1][2][0] - 1] = array_keys($positionList)[$playerIndex1];
        foreach (array_values($positionList)[$playerIndex1][2] as $p2Position) {
            if ($tmp[$p2Position - 1] == 0) {
                $tmp[$p2Position - 1] = array_keys($positionList)[$playerIndex2];
                break;
            }
        }
        $tmp[array_search(0, $tmp)] = array_keys($positionList)[$playerIndex3];
        return $tmp;
    }

    //根据场次获取选位和概率
    private function getTeamPositionConfigByNum(int $firstChoiceNum): array
    {
        $tmp = null;
        $luckNum = random_int(1, 100);
        $pr = 0;
        $positionConfig = $this->getTable(TemplateDefine::TYPE_RANK_TEAM_POSITION);
        foreach ($positionConfig as $num => $config) {
            if ($firstChoiceNum >= $num) {
                $tmp = $config;
            } else {
                break;
            }
        }
        if (is_null($tmp)) {
            $tmp = $positionConfig[array_key_first($positionConfig)];
        }
        //计算位置概率
        $pr += $tmp[TemplateRankPosition::Ratio1];
        if ($pr >= $luckNum) {
            return array(
                1 => $tmp[TemplateRankPosition::Ratio1],
                2 => $tmp[TemplateRankPosition::Ratio2],
                3 => $tmp[TemplateRankPosition::Ratio3],
            );
        }
        $pr += $tmp[TemplateRankPosition::Ratio2];
        if ($pr >= $luckNum) {
            return array(
                2 => $tmp[TemplateRankPosition::Ratio2],
                3 => $tmp[TemplateRankPosition::Ratio3],
            );
        }
        return array(
            3 => $tmp[TemplateRankPosition::Ratio3],
        );
    }

    // 匹配返回结果处理
    public function pvpMatchingRecv(array $msgData): bool
    {
        $playerList = $msgData[PvpMsgData::PLAYER_LIST];
        $MatchRecvMsg = new GCPVPMatchingSuccess();
        $MatchRecvMsg->setIp($msgData[PvpMsgData::IP]);
        $MatchRecvMsg->setPort($msgData[PvpMsgData::PORT]);
        $MatchRecvMsg->setSceneId($msgData[PvpMsgData::MAP_ID]);
        $MatchRecvMsg->setMatchType(GameConstantDefine::MATCH_MODE_TEAM_PAI_WEI);
        $players = array();
        $joinID = 0;
        //组队排位,匹配成功后,不需要赛车,在准备界面选车
        foreach ($playerList as $playerData) {
            if($this->playerId == $playerData[PvpMsgData::PLAYER_ID]) {
                $joinID = (int)$playerData[PvpMsgData::JOIN_ID];
                //检查更新首选位场次
                $this->updateTeamFirstChoice($playerData[PvpMsgData::POSITION]);
            }
            /**
             * @var PlayerShow $playerShow
             */
            $playerShow = $playerData[PvpMsgData::PLAYER_SHOW];
            /**
             * @var CarShow $carShow
             */
            $carShow = $playerData[PvpMsgData::CAR_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($playerShow->getContinuityWin());
            $player->setCarTplId($carShow->getCarTplID())
                ->setExteriorRefit($carShow->getExteriorRefit())
                ->setProficiencyLv($carShow->getProficiencyLv())
                ->setProficiency($carShow->getProficiency())
                ->setCarLv($carShow->getCarLv())
                ->setLevel($playerShow->getLevel())
                ->setDan($playerShow->getDan());
            $players[] = $player;
        }
        $MatchRecvMsg->setJoinId($joinID);
        $MatchRecvMsg->setPInfo($players);
        $MatchRecvMsg->setAInfo($msgData[PvpMsgData::AI_INFO]);
        if ($this->addPacket(PacketId::GC_PVPMatchingSuccess, $MatchRecvMsg, $this->playerId)) {
            LogMark::getInstance()->markInfo(
                '[PVPFlowLog][TeamRankingModel] match send msg:',
                array("packet" => $MatchRecvMsg->serializeToJsonString()));
            $changeData = array(
                RecordData::MATCHING_DATA => $MatchRecvMsg->serializeToJsonString()
            );
            $this->updateRecordData($this->playerId, $joinID, $changeData);
            return true;
        }
        LogMark::getInstance()->markInfo(
            '[PVPFlowLog][TeamRankingModel] match send msg fail:',
            array("packet" => $MatchRecvMsg->serializeToJsonString()));
        return false;
    }

    /**
     * PVP结算--组队排位赛
     * @param array $playerList
     * @param array $breakingRecordInfo [playerId=>RecordBreakingInfo]
     * @return bool
     */
    public function matchSettlement(array $playerList, array $breakingRecordInfo): bool
    {
        LogMark::getInstance()->markDebug(
            "[PVPFlowLog][TeamRankingModel] start pvp team ranking matchSettlement",
            $playerList
        );
        //配置
        $this->constConfigData = $this->getTable(TemplateDefine::TYPE_CONST);
        if (is_null($this->constConfigData)) {
            LogMark::getInstance()->markWarn(
                GameErrorCode::TEMPLATE_ID_NOT_FOUND,
                "[PVPFlowLog][TeamRankingModel] TYPE_CONST tpl table not found",
                array(
                    "TemplateTable" => TemplateDefine::TYPE_CONST
                )
            );
            return false;
        }
        $myRaceResult = null;
        $pIdRank = [];      //playerId=>rank
        $allPlayerParameter = array();  //结算参数
        $mvpPlayerId = null;
        //队伍获胜人数
        $teamWinNum = array(
            1 => 0,
            2 => 0
        );
        foreach ($playerList as $pid => $raceResult) {
            /**
             * @var RaceResultData $raceResult
             */
            //玩家自己结算消息处理
            if ($raceResult->_playerId == $this->playerId) {
                $myRaceResult = $raceResult;
                $this->joinId = $raceResult->_joinId;
            }
            if ($raceResult->_mvpIcon) {
                $mvpPlayerId = $raceResult->_playerId;
            }
            $pIdRank[$raceResult->_playerId] = $raceResult->_rank;
            //添加战斗通用返回消息
            $this->addRaceResultMessage($raceResult);
            $allPlayerParameter[] = $raceResult->parameter;
            //检查队伍获胜人数
            if ($raceResult->_isWin) {
                $teamWinNum[$raceResult->_groupId]++;
            } else {
                $teamWinNum[$raceResult->_groupId]--;
            }
        }
        //自己队伍获胜人数
        $myRaceResult->teamWinNum = $teamWinNum[$myRaceResult->_groupId];
        //玩家比赛结算
        $record = $this->matchSettlementPlayer($myRaceResult, $pIdRank);
        //每个玩家结算参数
        $this->sendMessage->setParameter($allPlayerParameter);
        //破记录信息
        $this->sendMessage->setMyBreakingInfo($breakingRecordInfo[$this->playerId]);
        $this->sendMessage->setMvpBreakingInfo($breakingRecordInfo[$mvpPlayerId]);
        //发送消息
        $this->sendMessage($this->playerId);
        //记录打点日志
        $this->addCompletaMatchLog($record, $myRaceResult, $playerList);
        return true;
    }

    //玩家比赛结算 有加分项待确定
    public function matchSettlementPlayer(RaceResultData $raceResult, array $pIdRank): RecordData
    {
        //积分配置表
        $this->paiweiConfigData = $this->getTable(TemplateDefine::TYPE_INTEGRAL);
        if (is_null($this->paiweiConfigData)) {
            LogMark::getInstance()->markWarn(
                GameErrorCode::TEMPLATE_ID_NOT_FOUND,
                "[PVPFlowLog][TeamRankingModel] pvp ranking ConfigData tpl table not found",
                array(
                    "TemplateTable" => TemplateDefine::TYPE_INTEGRAL
                )
            );
        }
        //检查赛季状态,关闭状态不给积分和奖励
        $seasonStatus = $this->getCommonValueByModel(ModelTypeDefine::SEASON_STATUS);
        $seasonIsOpen = false;
        if (!is_null($seasonStatus) && $seasonStatus == GameConstantDefine::SEASON_STATUS_OPEN) {
            $seasonIsOpen = true;
        }
        //设置团队胜利
        $this->isWin = $raceResult->_teamWin;
        //车辆信息 获取玩家当前默认的车
        $carConfigData = $this->getTitle(TemplateDefine::TYPE_CAR, $raceResult->_carId);
        $this->carPositioning = $carConfigData[TemplateCar::Positioning];

        $reward = array();
        $rewardMessage = array();
        $score = $guardScore = $carProficiency = $exp = $carScore = 0;
        $record = $this->getRecordData();
        if ($seasonIsOpen) {
            //获取排位赛积分
            [$score, $guardScore] = $this->getPaiweiScore($raceResult);
            //更新积分
            $this->updateRankingData($score, $guardScore, $this->isWin);

            //获取道具奖励
            $reward = array();
            $this->getReward($reward, $raceResult->_carId);
            // 比赛模式获取道具
            $this->getModeReward($reward, $raceResult->_modeType);
            $rewardMessage = array();
            $this->setLogAddItemSource(GameConstantDefine::ITEM_ADD_SOURCE_PVP_SETTLEMENT);
            $this->gainItemArr($reward);
            foreach ($reward as $itemId => $num) {
                //道具奖励消息
                $ri = new RewardItem();
                $ri->setId($itemId);
                $ri->setNum($num);
                $rewardMessage[] = $ri;
            }
            //车辆熟练度
            $carProficiency = $this->getCarProficiency($raceResult, $raceResult->_teamWin);
            $this->addCarProficiency($raceResult->_carId, $carProficiency, $raceResult->_modeType);

            // 经验
            $exp = $this->getAccountLvExp($raceResult->_teamWin, $raceResult->_modeType);
            $this->addPlayerExp($exp, $raceResult->_modeType);

            //计算车辆评分
            $carScore = $this->getCarScore($raceResult, $carProficiency);
        }

        //添加玩家结算奖励消息
        $this->sendMessage = new GCRaceResult();
        $this->sendMessage->setCarProficiencyArray($this->proficiencyArray);
        $this->sendMessage->setAddCarProficiency($carProficiency);
        $this->sendMessage->setAddExp($exp);
        $this->sendMessage->setAddScore($score);
        $this->sendMessage->setAddGuardScore($guardScore);
        $this->sendMessage->setCarScore($carScore);
        $this->sendMessage->setScoreArray($this->scoreArray);
        $this->sendMessage->setItem($rewardMessage);

        //当前段位信息
        $paiweiLevel = $this->getPaiweiLevel();
        $this->sendMessage->setScore($paiweiLevel->score);
        $this->sendMessage->setMaxLevelId($paiweiLevel->maxLevelId);
        $this->sendMessage->setGuardScore($paiweiLevel->guardScore);
        $this->sendMessage->setSeasonId($paiweiLevel->seasonId);
        $this->sendMessage->setMatchId($record->matchUID);

        if ($seasonIsOpen) {
            //触发任务
            $param = array(
                GameConstantDefine::EVENT_KEY_NUM => $score,
                GameConstantDefine::EVENT_KEY_PAI_WEI_LEVEL => $paiweiLevel->levelId
            );
            $this->triggerEvent(EventTypeDefine::EVENT_TYPE_TASK_PAI_WEI_SCORE, $param, false);

            //比赛统计数据
            $this->tidyStatisticsData($raceResult);
            //更新排行榜
            $this->changeRankMap($raceResult->_costTime, $record->mapID);
            $this->updateRankData($raceResult);
            //触发任务
            $this->triggerFinishPVPEvent($raceResult, $record, $raceResult->_teamWin, $this->playerId);
            // 自己获得mvp 获得赛季积分
            if($raceResult->_mvpIcon) {
                $this->updateSeasonScore(TemplateSeasonRewardCondition::RANK_MVP);
            }
            // 增加赛季积分
            $this->updateSeasonScore(TemplateSeasonRewardCondition::PLAY_RANK);
        }
        //更新房间状态
        $this->changePlayerAndRoomState($record->roomID);
        //更新比赛记录
        $this->updateRecord($raceResult, $this->playerId);
        //更新好友比赛记录
        $this->updateLastGame($pIdRank, $this->playerId, $record->mapID, $record->matchingData);
        //清空比赛状态
        $this->clearJoinId();
        return $record;
    }

    //获取排位赛积分
    private function getPaiweiScore(RaceResultData $raceResult): array
    {
        $score = 0;
        $guardScore = 0;
        //计算通用分
        $paiweiLevel = $this->getPaiweiLevel();
        //冲线==完成比赛
        if ($raceResult->_costTime > 0) {
            $score += $this->getPaiweiConfigValue(TemplateIntegral::CHONG_XIAN, $paiweiLevel);
            $guardScore += $this->getPaiweiConfigValue(TemplateIntegral::G_CHONG_XIAN, $paiweiLevel);
        }
        //金牌表现==获得徽章
        if ($raceResult->_raceIcon || $raceResult->_jamIcon || $raceResult->_helpIcon) {
            $score += $this->getPaiweiConfigValue(TemplateIntegral::JIN_PAI_BIAO_XIAN, $paiweiLevel);
            $guardScore += $this->getPaiweiConfigValue(TemplateIntegral::G_JIN_PAI, $paiweiLevel);
        }
        //一路领先==领跑占比>=70%
        if ($raceResult->parameter->getLeadRatio() >= 0.7) {
            $score += $this->getPaiweiConfigValue(TemplateIntegral::YI_LU_LING_XIAN, $paiweiLevel);
            $guardScore += $this->getPaiweiConfigValue(TemplateIntegral::G_YI_LU_LING_XIAN, $paiweiLevel);
        }
        //比赛失败 加新手保护分
        if (!$raceResult->_teamWin) {
            $score += $this->getPaiweiConfigValue(TemplateIntegral::NEW_PLAYER_GUARD1, $paiweiLevel);
            $score += $this->getPaiweiConfigValue(TemplateIntegral::NEW_PLAYER_GUARD2, $paiweiLevel);
        }
        //每日首胜
        if ($this->isWin) {
            $score += $this->getPaiweiConfigValue(TemplateIntegral::DAILY_WIN, $paiweiLevel);
        }
        //连败
        if (!$this->isWin && $paiweiLevel->record < 0) {
            $score += $this->getPaiweiConfigValue(TemplateIntegral::CONTINUOUS_FAIL_GUARD, $paiweiLevel);
        }
        //连胜
        if ($this->isWin && $paiweiLevel->record > 0) {
            $guardScore += $this->getPaiweiConfigValue(TemplateIntegral::G_LIAN_SHENG, $paiweiLevel);
        }
        //个人积分
        $this->getPaiweiScoreTeam($raceResult, $score, $guardScore, $paiweiLevel);
        return array($score, $guardScore);
    }

    //排位赛积分--组队
    //临时队伍中对位胜利的数量大于敌方时判定为胜
    //临时队伍中对位胜利的数量小于敌方时判定为负
    //对位是指：将双方队伍中相同排名序列的玩家在总排名序列相比
    //若己方玩家排名序列高于敌方玩家，则判定对位胜利
    //若己方玩家排名序列低于敌方玩家，则判定对位失败
    //组队胜利,对位比较 获胜多的一方为胜方 对位全胜为完胜 全败为完败
    //组队第x名:总排名第x
    private function getPaiweiScoreTeam(RaceResultData $raceResult, &$score, &$guardScore, PaiweiLevelData $paiweiLevel)
    {
        //组队胜利
        if ($raceResult->_teamWin) {
            $score += $this->getPaiweiConfigValue(TemplateIntegral::TEAM_WIN, $paiweiLevel);
            //组队胜利保护分
            $guardScore += $this->getPaiweiConfigValue(TemplateIntegral::G_TEAM_WIN, $paiweiLevel);
        } else {
            $score += $this->getPaiweiConfigValue(TemplateIntegral::TEAM_FAIL, $paiweiLevel);
        }
        //组队第一名：团队赛中第一个冲线
        if ($raceResult->_rank == 1) {
            $score += $this->getPaiweiConfigValue(TemplateIntegral::TEAM_NO1, $paiweiLevel);
            //组队第一保护分
            $guardScore += $this->getPaiweiConfigValue(TemplateIntegral::G_TEAM_NO1, $paiweiLevel);
        }
        //MVP
        if ($raceResult->_mvpIcon) {
            $score += $this->getPaiweiConfigValue(TemplateIntegral::TEAM_MVP, $paiweiLevel);
        }
        //组队第二名：团队赛中第二个冲线
        if ($raceResult->_rank == 2) {
            //组队第二保护分
            $guardScore += $this->getPaiweiConfigValue(TemplateIntegral::G_TEAM_NO2, $paiweiLevel);
        }
        //完胜
        if ($raceResult->teamWinNum == 3) {
            $score += $this->getPaiweiConfigValue(TemplateIntegral::TEAM_WAN_SHENG, $paiweiLevel);
            //完胜保护分
            $guardScore += $this->getPaiweiConfigValue(TemplateIntegral::G_WAN_SHENG, $paiweiLevel);
        }
        //对位胜利保护分
        if ($raceResult->_isWin) {
            $guardScore += $this->getPaiweiConfigValue(TemplateIntegral::G_DUI_WEI_WIN, $paiweiLevel);
        }
        //亲密关系--组队胜利后,邀请或被邀请的玩家有亲密关系
        if ($raceResult->_teamWin) {
            $record = $this->getRecordData();
            if (is_null($record)) {
                return;
            }
            if ($this->checkPlayerWithIntimacyFriend($record->roomID, $this->playerId)) {
                $score += $this->getPaiweiConfigValue(TemplateIntegral::TEAM_FRIEND_INTIMACY, $paiweiLevel);
            }
        }
    }

    //根据Id获得排位赛积分表对应积分
    private function getPaiweiConfigValue(int $id, PaiweiLevelData $levelData): int
    {
        if (!isset($this->paiweiConfigData[$id])) {
            LogMark::getInstance()->markWarn(
                GameErrorCode::TEMPLATE_ID_NOT_FOUND,
                "[PVPFlowLog][TeamRankingModel] tpl table not found",
                array(
                    "TemplateTable" => TemplateDefine::TYPE_INTEGRAL,
                    "id" => $id
                )
            );
            return 0;
        }
        //检查生效段位范围和场次
        if ($this->paiweiConfigData[$id][TemplateIntegral::MatchNum] == 0) {
            //0不生效
            return 0;
        }
        if ($levelData->levelId >= $this->paiweiConfigData[$id][TemplateIntegral::LvMin] &&
            $levelData->levelId <= $this->paiweiConfigData[$id][TemplateIntegral::LvMax]) {
            if ($this->paiweiConfigData[$id][TemplateIntegral::MatchNum] == -1) {
                //不限次数
                if ($this->paiweiConfigData[$id][TemplateIntegral::BpType] == 1) {
                    $this->scoreArray[] = $id;
                }
                return $this->paiweiConfigData[$id][TemplateIntegral::BpNum];
            }
            if ($levelData->dailyMatchNum <= $this->paiweiConfigData[$id][TemplateIntegral::MatchNum]) {
                if ($this->paiweiConfigData[$id][TemplateIntegral::BpType] == 1) {
                    $this->scoreArray[] = $id;
                }
                return $this->paiweiConfigData[$id][TemplateIntegral::BpNum];
            }
        }
        return 0;
    }


    //匹配消息
    public function joinRoomMsg(int $code) {
        $this->startMatchingMsg->setCode($code);
    }

    public function joinRoomMsgSend() {
        $this->addPacket(PacketId::GC_StartMatching, $this->startMatchingMsg, $this->playerId);
    }

    public function addJoinRoomMsg(array $players) {
        foreach($players as $id => $p) {
            $this->addPacket(PacketId::GC_StartMatching, $this->startMatchingMsg, $id);
        }
    }
}