<?php

/**
 * 匹配人数不足 加入AI
 */

namespace Game\Logic\Pvp;

use Framework\Define\ErrorDefine;
use Framework\Log\LogMark;
use Framework\MVC\ModelManager;
use Framework\DB\Handler\PlayerDBHandler;
use Framework\Logic\TemplateHelp;
use Game\Constant\ConstTemplate\TemplateConst;
use Game\Constant\ConstTemplate\TemplateGenerateAi;
use Game\Constant\ConstTemplate\TemplatePVPMatch;
use Game\Constant\DBTableDefine;
use Game\Constant\GameConstantDefine;
use Game\Constant\TemplateDefine;
use Game\Data\PaiWei\PaiweiLevelData;
use Game\Data\PvpPacket\PvpMsgData;
use Game\Logic\GenerateAiLogic;
use Game\Logic\PaiweiLevelLogic;
use Game\Protobuf\AIInfo;
use Exception;
use Game\Protobuf\PlayerShow;

trait MatchAILogic
{
    use PlayerDBHandler;
    use TemplateHelp;

    use GenerateAiLogic;
    use PaiweiLevelLogic;

    /**
     * @param int $matchType
     * @param array $playerList
     * @param int $mapId
     * @return array protobuf AIInfo
     */
    public function addMatchAI(int $matchType, array $playerList, int $mapId = 0): array
    {
        ModelManager::getInstance()->setPlayerId(0);
        $aiPlayersMessage = array();
        //检查比赛模式最大人数
        $maxNum = $this->getMatchMaxPlayer($matchType);
        $needAINum = $maxNum - count($playerList);
        if ($needAINum <= 0) {
            return $aiPlayersMessage;
        }
        //根据比赛类型 创建AI
        switch ($matchType)
        {
            case GameConstantDefine::MATCH_MODE_SINGLE_PRACTISE:
                $this->addSinglePracticeAI($needAINum, $aiPlayersMessage);
                break;
            case GameConstantDefine::MATCH_MODE_TEAM_PRACTISE:
                $this->addTeamPracticeAI($needAINum, $aiPlayersMessage, $playerList);
                break;
            case GameConstantDefine::MATCH_MODE_SINGLE_PAI_WEI:
                $this->addSingleRankingAI($needAINum, $aiPlayersMessage, $playerList);
                break;
            case GameConstantDefine::MATCH_MODE_TEAM_PAI_WEI:
                $this->addTeamRankingAI($needAINum, $aiPlayersMessage, $playerList);
                break;
            case GameConstantDefine::MATCH_MODE_SINGLE:
                $this->addSingleAI($needAINum, $aiPlayersMessage, $playerList);
                break;
            case GameConstantDefine::MATCH_MODE_TEAM:
                $this->addTeamAI($needAINum, $aiPlayersMessage, $playerList);
                break;
            case GameConstantDefine::MATCH_MODE_PRACTICE:
                break;
            case GameConstantDefine::MATCH_MODE_SCUFFLE:
                $this->addTeamScuffleAI($needAINum, $aiPlayersMessage, $playerList);
                break;
        }
        //随机AI等级和段位
        [$avgLevel, $avgDan] = $this->getAvgPlayerLevel($playerList);
        foreach ($aiPlayersMessage as $idx => $aiInfo) {
            /**
             * @var AIInfo $aiInfo
             */
            [$randomLevel, $randomDan] = $this->getRandomLevel($avgLevel, $avgDan);
            $aiInfo->setLevel($randomLevel);
            $aiInfo->setDan($randomDan);
        }
        return $aiPlayersMessage;
    }

    //个人练习赛--初级AI
    private function addSinglePracticeAI(int $needAINum, array &$aiPlayersMessage)
    {
        $this->getAIPlayerFromDB($this->getPracticeAILevel(), $needAINum, $aiPlayersMessage);
    }

    //团队练习赛--初级AI
    private function addTeamPracticeAI(int $needAINum, array &$aiPlayersMessage, array $playerList)
    {
        //计算需要补充的groupId
        $needGroupIds = $this->getTeamGroupIds($playerList, $needAINum);
        $this->getAIPlayerFromDB($this->getPracticeAILevel(), $needAINum, $aiPlayersMessage);
        foreach ($aiPlayersMessage as $idx => $aiInfo) {
            /**
             * @var AIInfo $aiInfo
             */
            $aiInfo->setGroupID($needGroupIds[$idx]);
        }
    }

    //个人排位赛
    private function addSingleRankingAI(int $needAINum, array &$aiPlayersMessage, array $playerList)
    {
        $AILevel = $this->getPaiWeiAILevel($playerList);
        //计算需要补充的位置
        $positionList = $this->getSinglePositionList($playerList);
        $this->getAIPlayerFromDB($AILevel, $needAINum, $aiPlayersMessage);
        foreach ($aiPlayersMessage as $idx => $aiInfo) {
            /**
             * @var AIInfo $aiInfo
             */
            $aiInfo->setPosition($positionList[$idx]);
        }
    }

    // 个人模式
    private function addSingleAI(int $needAINum, array &$aiPlayersMessage, array $playerList)
    {
        foreach($playerList as $item) {
            // 判断是否添加ai车
            if(empty($item[PvpMsgData::PARAM])) {
                return true;
            }
        }
        $AILevel = $this->getPracticeAILevel();
        //计算需要补充的位置
        $positionList = $this->getSinglePositionList($playerList);
        $this->getAIPlayerFromDB($AILevel, $needAINum, $aiPlayersMessage);
        foreach ($aiPlayersMessage as $idx => $aiInfo) {
            /**
             * @var AIInfo $aiInfo
             */
            $aiInfo->setPosition($positionList[$idx]);
        }
    }

    //团队排位赛
    private function addTeamRankingAI(int $needAINum, array &$aiPlayersMessage, array $playerList)
    {
        $AILevel = $this->getPaiWeiAILevel($playerList);
        //计算需要补充的groupId
        $needGroupIds = $this->getTeamGroupIds($playerList, $needAINum);
        //计算需要补充的位置
        [$positionList1, $positionList2] = $this->getTeamPositionList($playerList);
        $positionArr = array_merge($positionList1, $positionList2);
        $this->getAIPlayerFromDB($AILevel, $needAINum, $aiPlayersMessage, $positionArr);
        foreach ($aiPlayersMessage as $idx => $aiInfo) {
            /**
             * @var AIInfo $aiInfo
             */
            $aiInfo->setGroupID($needGroupIds[$idx]);
            if ($aiInfo->getGroupID() == 1) {
                $position = array_shift($positionList1);
            } else {
                $position = array_shift($positionList2);
            }
            $aiInfo->setPosition($position);
        }
    }

    // 团队模式
    private function addTeamAI(int $needAINum, array &$aiPlayersMessage, array $playerList)
    {
        $AILevel = $this->getPaiWeiAILevel($playerList);
        //计算需要补充的groupId
        $needGroupIds = $this->getTeamGroupIds($playerList, $needAINum);
        //计算需要补充的位置
        [$positionList1, $positionList2] = $this->getTeamPositionList($playerList);
        $this->getAIPlayerFromDB($AILevel, $needAINum, $aiPlayersMessage);
        foreach ($aiPlayersMessage as $idx => $aiInfo) {
            /**
             * @var AIInfo $aiInfo
             */
            $aiInfo->setGroupID($needGroupIds[$idx]);
            if ($aiInfo->getGroupID() == 1) {
                $position = array_shift($positionList1);
            } else {
                $position = array_shift($positionList2);
            }
            $aiInfo->setPosition($position);
        }
    }

    //大乱斗--初级AI
    private function addTeamScuffleAI(int $needAINum, array &$aiPlayersMessage, array $playerList)
    {
        //计算需要补充的groupId
        $needGroupIds = $this->getTeamGroupIds($playerList, $needAINum);
        $this->getAIPlayerFromDB($this->getPracticeAILevel(), $needAINum, $aiPlayersMessage);
        $avgScore = $this->getScuffleAvgScore($playerList);
        foreach ($aiPlayersMessage as $idx => $aiInfo) {
            /**
             * @var AIInfo $aiInfo
             */
            $aiInfo->setGroupID($needGroupIds[$idx]);
            $aiInfo->setScuffleScore($this->getRandomScuffleScore($avgScore));
        }
    }

    //练习赛统一为初级AI
    private function getPracticeAILevel(): int
    {
        return TemplateGenerateAi::AI_LEVEL_1;
    }

    //检查团队赛groupId,分配不足的groupId
    private function getTeamGroupIds(array $playerList, int $needAINum): array
    {
        //每队最大人数
        $groupIds = array(
            1 => 3,
            2 => 3
        );
        foreach ($playerList as $player) {
            $groupIds[$player[PvpMsgData::GROUP_ID]]--;
        }
        $needGroupIds = array();
        while ($needAINum > 0) {
            if ($groupIds[1] > 0) {
                $groupId = 1;
                $groupIds[1]--;
            } else {
                $groupId = 2;
            }
            $needGroupIds[] = $groupId;
            $needAINum--;
        }
        return $needGroupIds;
    }

    //获取单人排位赛可选的位置
    private function getSinglePositionList(array $playerList): array
    {
        //每队最大人数
        $positionList = array(1, 2, 3, 4, 5, 6);
        foreach ($playerList as $player) {
            $idx = array_search($player[PvpMsgData::POSITION], $positionList);
            if (!is_bool($idx)) {
                unset($positionList[$idx]);
            }
        }
        sort($positionList);
        return $positionList;
    }

    //获取组队排位赛可选的位置
    private function getTeamPositionList(array $playerList): array
    {
        //每队最大人数
        //1队1,3,5 2队2,4,6
        $positionList1 = array(1, 3, 5);
        $positionList2 = array(2, 4, 6);
        foreach ($playerList as $player) {
            if ($player[PvpMsgData::GROUP_ID] == 1) {
                $idx = array_search($player[PvpMsgData::POSITION], $positionList1);
                if (!is_bool($idx)) {
                    unset($positionList1[$idx]);
                }
            } else {
                $idx = array_search($player[PvpMsgData::POSITION], $positionList2);
                if (!is_bool($idx)) {
                    unset($positionList2[$idx]);
                }
            }
        }
        sort($positionList1);
        sort($positionList2);
        return array($positionList1, $positionList2);
    }

    //排位赛-获取玩家AI等级
    private function getPaiWeiAILevel(array $playerList): int
    {
        $isBaoDi = false;   //触发保底AI
        $tmpLevel = 0;
        foreach ($playerList as $player) {
            $playerRank = $this->getTargetPaiWeiLevel($player[PvpMsgData::PLAYER_ID]);
            $tmpLevel += $playerRank->levelId;
            if ($playerRank->levelId <= 11 && $playerRank->record <= -4) {
                //连输4场 触发保底AI 只在黄金以下段位生效（包括黄金）
                $isBaoDi = true;
            }
        }
        //平均等级
        $avgLevel = (int)($tmpLevel / count($playerList));
        if ($isBaoDi) {
            return TemplateGenerateAi::AI_LEVEL_1;
        }
        return $this->getPaiWeiAILevelByRankLevel($avgLevel);
    }

    //排位赛-根据玩家平均段位 获取AI等级
    private function getPaiWeiAILevelByRankLevel(int $level): int
    {
        //青铜、白银、黄金分段使用初级AI
        //铂金、钻石分段使用中级AI
        //大师、荣耀分段使用高级AI
        if ($level <= 11) {
            return TemplateGenerateAi::AI_LEVEL_1;
        }
        if ($level > 11 && $level <= 21) {
            return TemplateGenerateAi::AI_LEVEL_2;
        }
        return TemplateGenerateAi::AI_LEVEL_3;
    }

    //获得大乱斗平均分
    private function getScuffleAvgScore(array $playerList): int
    {
        $score = 0;
        foreach ($playerList as $player) {
            /**
             * @var PlayerShow $playerShow
             */
            $playerShow = $player[PvpMsgData::PLAYER_SHOW];
            $score += $playerShow->getScuffleScore();
        }
        return (int) $score / count($playerList);
    }

    //随机AI大乱斗积分
    private function getRandomScuffleScore(int $avgScore): int
    {
        //分数范围
        $gap = 100;
        return random_int(max(1000, $avgScore - $gap), ($avgScore + $gap));
    }

    //获得玩家平均等级和段位
    private function getAvgPlayerLevel(array $playerList): array
    {
        $playerLevel = $playerDan = 0;
        foreach ($playerList as $player) {
            /**
             * @var PlayerShow $playerShow
             */
            $playerShow = $player[PvpMsgData::PLAYER_SHOW];
            $playerLevel += $playerShow->getLevel();
            $playerDan += $playerShow->getDan();
        }
        return array(
            (int) $playerLevel / count($playerList),
            (int) $playerDan / count($playerList)
        );
    }

    //随机AI等级和段位
    private function getRandomLevel(int $avgLevel, int $avgDan): array
    {
        //等级上限50 段位上限24(大师1)
        $levelGap = $this->getTerm(
            TemplateDefine::TYPE_CONST,
            TemplateConst::Const_AI_RANDOM_LEVEL_RANGE,
            TemplateConst::ConstNum
        );
        $danGap = $this->getTerm(
            TemplateDefine::TYPE_CONST,
            TemplateConst::Const_AI_RANDOM_DAN_RANGE,
            TemplateConst::ConstNum
        );
        $minLevel = max(1, $avgLevel - $levelGap);
        $maxLevel = $avgLevel + $levelGap > 50 ? 50 : $avgLevel + $levelGap;
        $minDan = max(1, $avgDan - $danGap);
        $maxDan = $avgDan + $danGap > 24 ? 24 : $avgDan + $danGap;

        return array(
            random_int($minLevel, $maxLevel),
            random_int($minDan, $maxDan)
        );
    }

    private function getAIPlayerFromDB(int $level, int $num, array &$aiPlayersMessage, array $positionArr = array())
    {
        //根据人数,平均分配对应等级的AI
        $config = $this->getTitle(TemplateDefine::TYPE_GENERATE_AI, $level);
        $maxAiIds = count($config[TemplateGenerateAi::AIIds]);
        $data = array();
        //根据数量 随机AI Id
        $base = (int)(GameConstantDefine::AI_PLAYER_MAX_ID / $num);
        $t = 0;
        $i = 0;
        while ($t < $num) {
            $position = 0;
            if (!empty($positionArr)) {
                $tmp = array_shift($positionArr);
                if (!is_null($tmp)) {
                    $position = $tmp;
                    //位置转换
                    if ($position == 1 || $position == 2) {
                        $position = 1;
                    } elseif ($position == 3 || $position == 4) {
                        $position = 2;
                    } elseif ($position == 5 || $position == 6) {
                        $position = 3;
                    } else {
                        $position = 0;
                    }
                }
            }
            $id = random_int($base * $t + 1, $base * ($t + 1));
            $aiDBId = $this->makeAIPlayerId($level, $id, $position);
            $AITplId = $config[TemplateGenerateAi::AIIds][$i];
            $t++;
            $i++;
            if ($i >= $maxAiIds) {
                $i = 0;
            }
            $this->searchTerm(
                $ret,
                DBTableDefine::TABLE_AI_PLAYER,
                0,
                $this->getAITitle($level, $AITplId),
                $aiDBId
            );
            $data[] = $ret;
        }
        //反序列化 AIData放入$aiPlayersMessage
        foreach ($data as $aiInfoJsonStr) {
            $aiInfo = new AIInfo();
            try {
                $aiInfo->mergeFromJsonString($aiInfoJsonStr);
            } catch (Exception $e) {
                LogMark::getInstance()->markError(
                    ErrorDefine::ERROR_INTERNAL,
                    "[MatchAILogic] AI player json string error",
                    array(
                        $aiInfoJsonStr
                    )
                );
                continue;
            }
            $aiPlayersMessage[] = $aiInfo;
        }
    }

    private function getMatchMaxPlayer(int $matchType): int
    {
        $maxPlayer = 0;
        $matchConfig = $this->getTitle(TemplateDefine::TYPE_PVP_MATCH, $matchType);
        if (is_null($matchConfig)) {
            LogMark::getInstance()->markError(
                ErrorDefine::TEMPLATE_CONFIG_NOT_FOUND,
                "[MatchAILogic] not found PVPMatch config",
            );
            return $maxPlayer;
        }
        return $matchConfig[TemplatePVPMatch::MaxPlayer];
    }

    public function getAITitle(int $level, int $AITplId): string
    {
        return $level. "#" . $AITplId;
    }
}
