<?php

/**
 * 增加玩家经验
 */

namespace Game\Method\Player;

use Framework\Log\LogMark;
use Framework\Logic\TemplateHelp;
use Framework\MVC\ModelManager;
use Framework\Network\SendMessage;
use Game\Constant\ConstTemplate\TemplateCompetitionMode;
use Game\Constant\ConstTemplate\TemplatePlayerLevel;
use Game\Constant\EventTypeDefine;
use Game\Constant\GameConstantDefine;
use Game\Constant\ModelTypeDefine;
use Game\Constant\TemplateDefine;
use Game\Data\AccountData;
use Game\Logic\ItemLogic;
use Game\Model\AccountModel;
use Game\Protobuf\GCUpdatePlayerExp;
use Game\Protobuf\PacketId;

trait AddPlayerExp
{
    use TemplateHelp;
    use ItemLogic;

    //增加玩家经验
    public function addPlayerExp(int $addExp, int $matchType = 0, bool $isGm = false, int $playerID = 0)
    {
        if ($addExp <= 0) {
            return;
        }
        LogMark::getInstance()->markInfo(
            "[AddPlayerExp]",
            array(
                "addExp" => $addExp,
                "matchType" => $matchType,
                "isGm" => $isGm,
                "playerId" => $playerID
            )
        );
        //检查比赛模式是否加经验
        if ($matchType > 0) {
            $config = $this->getTitle(TemplateDefine::TYPE_COMPETITION_MODE, $matchType);
            if (is_null($config)) {
                return;
            }
            if ($config[TemplateCompetitionMode::WhetherExp] == 0) {
                return;
            }
        }
        //双倍经验检查
        if ($this->checkBuffActivate(AccountData::DB_BUFF_DOUBLE_EXP)) {
            $addExp *= 2;
        }
        /**
         * @var AccountModel $account
         */
        $account = ModelManager::getInstance()->getModel(ModelTypeDefine::ACCOUNT);
        $account->searchAccount($playerInfo);
        $level = $playerInfo[AccountData::DB_LEVEL] ?? 1;
        $exp = $playerInfo[AccountData::DB_EXP] ?? 0;
        $exp += $addExp;
        //最高级检查
        $config = $this->getTable(TemplateDefine::TYPE_PLAYER_LEVEL);
        $maxLevel = count($config);
        if ($level >= $maxLevel) {
            $data = [
                AccountData::DB_EXP => $exp,
            ];
            $account->saveAccount($data);
            if($isGm) {
                $this->sendPacketUpdatePlayerExpMessage($level, $exp, $playerID);
            } else {
                $this->sendUpdatePlayerExpMessage($level, $exp);
            }
            return;
        }
        $addReward = array();
        foreach ($config as $id => $configData) {
            $tmpLv = $configData[TemplatePlayerLevel::Level];
            if ($level > $tmpLv) {
                continue;
            }
            if ($level == $tmpLv && $exp >= $configData[TemplatePlayerLevel::Exp]) {
                $level++;
                $exp -= $configData[TemplatePlayerLevel::Exp];
                //升级 给下一级奖励
                if (isset($config[$level][TemplatePlayerLevel::Reward])) {
                    foreach ($config[$level][TemplatePlayerLevel::Reward] as $itemId => $num) {
                        isset($addReward[$itemId]) ? $addReward[$itemId] += $num : $addReward[$itemId] = $num;
                    }
                }
            }
            if ($tmpLv > $level) {
                break;
            }
            if ($level >= $maxLevel) {
                break;
            }
        }
        $data = [
            AccountData::DB_EXP => $exp,
            AccountData::DB_LEVEL => $level
        ];
        $account->saveAccount($data);
        if($isGm) {
            $this->sendPacketUpdatePlayerExpMessage($level, $exp, $playerID);
        } else {
            $this->sendUpdatePlayerExpMessage($level, $exp);
        }
        $param = array(
            GameConstantDefine::EVENT_KEY_PLAYER_LEVEL => $level,
        );
//        $this->triggerEvent(EventTypeDefine::EVENT_TYPE_TASK_PLAYER_LEVEL, $param);
        if (!empty($addReward)) {
            $this->setLogAddItemSource(GameConstantDefine::ITEM_ADD_SOURCE_GROW_UP_REWARD);
            $this->gainItemArr($addReward);
        }
    }

    private function sendUpdatePlayerExpMessage(int $level, int $exp)
    {
        $message = new GCUpdatePlayerExp();
        $message->setLevel($level);
        $message->setExp($exp);
        SendMessage::getInstance()->sendClient(PacketId::GC_UpdatePlayerExp, $message);
    }

    private function sendPacketUpdatePlayerExpMessage(int $level, int $exp, $playerID)
    {
        $message = new GCUpdatePlayerExp();
        $message->setLevel($level);
        $message->setExp($exp);
        SendMessage::getInstance()->addPacket(PacketId::GC_UpdatePlayerExp, $message, $playerID);
    }
}
