<?php

/**
 * pve通用 驾照考试 试驾关卡 技巧教学
 */

namespace Game\Model\PVE;

use Framework\Log\LogMark;
use Framework\Logic\TemplateHelp;
use Framework\Network\SendMessage;
use Game\Constant\ClientErrorCode;
use Game\Constant\ConstTemplate\TemplateInitPlayer;
use Game\Constant\ConstTemplate\TemplateTale;
use Game\Constant\EventTypeDefine;
use Game\Constant\GameConstantDefine;
use Game\Constant\GameErrorCode;
use Game\Constant\TemplateDefine;
use Game\Data\PVE\CareerChapterData;
use Game\Data\PVE\CareerLevelData;
use Game\Data\PVE\DrivingLicenseData;
use Game\Data\PVE\DrivingPermitData;
use Game\Data\PVE\ExamData;
use Game\Data\PVE\LevelData;
use Game\Data\PVE\TeachingSkillChapterData;
use Game\Logic\EventLogic;
use Game\Operation\EventLog\EventLog_Manager;
use Game\Operation\EventLog\EventLogType;
use Game\Protobuf\DLDate;
use Game\Protobuf\GameLevel;
use Game\Protobuf\GCDrivingLicense;
use Game\Protobuf\GCGameLevelFinishLevelData;
use Game\Protobuf\GCTeachingSkill;
use Game\Protobuf\PacketId;

class PveModel
{
    use TemplateHelp;
    use EventLogic;

    private int $playerId;

    private ?array $initPlayerConfig = null;

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

    private function getInitPlayerConfig()
    {
        if (is_null($this->initPlayerConfig)) {
            $this->initPlayerConfig = $this->getTitle(TemplateDefine::TYPE_INIT_PLAYER, TemplateInitPlayer::DEFAULT_ID);
        }
    }

    //初始化
    public function onRegister()
    {
        $this->initCarrerLevel();
    }

    /**
     * 驾照相关
    */
    //获取驾照等级
    public function getDrivingLicenseLv(): int
    {
        $drivingLicenseData = new DrivingLicenseData($this->playerId);
        $drivingLicenseData->searchDB();
        return $drivingLicenseData->drivingLicenseLv;
    }

    //生成驾照
    public function makeDrivingLicense(int $chapterId)
    {
        $drivingLicenseData = new DrivingLicenseData($this->playerId);
        $drivingLicenseData->searchDB();
        if ($drivingLicenseData->drivingLicenseLv > TemplateTale::DRIVING_LICENSE_LEVEL_MAX) {
            return;
        }
        if ($drivingLicenseData->drivingLicenseLv >= $chapterId) {
            return;
        }
        ++$drivingLicenseData->drivingLicenseLv;
        $drivingLicenseData->updateDB();
        $this->sendDrivingLicenseMessage($drivingLicenseData);
        //触发任务
        $eventData = array(
            GameConstantDefine::EVENT_KEY_NUM => $drivingLicenseData->drivingLicenseLv,
        );
        $this->triggerEvent(EventTypeDefine::EVENT_TYPE_TASK_DRIVING_LICENSE_LEVEL, $eventData);
    }

    //驾照信息更新消息
    public function sendDrivingLicenseMessage(DrivingLicenseData $drivingLicenseData = null)
    {
        if (is_null($drivingLicenseData)) {
            $drivingLicenseData = new DrivingLicenseData($this->playerId);
            $drivingLicenseData->searchDB();
        }
        $sendMessage = new GCDrivingLicense();
        $sendMessage->setDrivingLicenseLv($drivingLicenseData->drivingLicenseLv);
        //返回已解锁的每个驾照的日期
        $examData = new ExamData($this->playerId);
        $dateMsg = array();
        for ($i = 1; $i <= $drivingLicenseData->drivingLicenseLv; $i++) {
            if (false == $examData->searchDB($i)) {
                continue;
            }
            $date = new DLDate();
            $date->setDrivingLicenseLv($examData->id);
            $date->setDrivingLicenseDate($examData->drivingLicenseDate);
            $dateMsg[] = $date;
        }
        $sendMessage->setDate($dateMsg);
        SendMessage::getInstance()->sendClient(PacketId::GC_DrivingLicense, $sendMessage);
    }

    //查询驾照章节
    public function getChapterData(int $chapterId): ExamData
    {
        $examData = new ExamData($this->playerId);
        $examData->searchDB($chapterId);
        if ($chapterId == TemplateTale::DRIVING_LICENSE_LEVEL_C && $examData->id == 0) {
            //创建
            $examData->createExam($chapterId);
        }
        return $examData;
    }

    //创建驾照章节
    public function createChapter(int $chapterId): ExamData
    {
        $examData = new ExamData($this->playerId);
        $examData->createExam($chapterId);
        return $examData;
    }

    //获取关卡信息
    public function getLevelData(int $levelId): LevelData
    {
        $levelData = new LevelData($this->playerId);
        $levelData->searchDB($levelId);
        return $levelData;
    }

    /**
     * 获取章节下已开通的全部关卡
     * @param int $chapterId
     * @return array levelId=>levelData
     */
    public function getAllLevelData(int $chapterId): array
    {
        $this->getInitPlayerConfig();
        $levelList = $this->initPlayerConfig[TemplateInitPlayer::DrivingLicenseLevel][$chapterId] ?? array();
        $arr = array();
        foreach ($levelList as $levelId) {
            $levelData = $this->getLevelData($levelId);
            if ($levelData->levelId != 0) {
                $arr[$levelData->levelId] = $levelData;
            }
        }
        if (empty($arr)) {
            //开启全部关卡
            foreach ($levelList as $levelId) {
                $levelData = $this->createLevel($levelId);
                if ($levelData->levelId != 0) {
                    $arr[$levelData->levelId] = $levelData;
                }
            }
        }
        return $arr;
    }

    //创建关卡
    public function createLevel(int $levelId): LevelData
    {
        $levelData = new LevelData($this->playerId);
        $levelData->initLevel($levelId);
        return $levelData;
    }

    /**
     * 技巧教学相关
     */
    //获取技巧教学等级
    public function getTeachingSkillLv(): int
    {
        $drivingLicenseData = new DrivingLicenseData($this->playerId);
        $drivingLicenseData->searchDB();
        return $drivingLicenseData->teachingSkillLv;
    }

    //查询技巧教学章节
    public function getTeachingSkillChapterData(int $chapterId): TeachingSkillChapterData
    {
        $data = new TeachingSkillChapterData($this->playerId);
        $data->searchDB($chapterId);
        if ($data->id == 0) {
            $data->createDB($chapterId);
        }
        return $data;
    }

    //创建技巧教学章节
    public function createTeachingSkillChapter(int $chapterId): TeachingSkillChapterData
    {
        $data = new TeachingSkillChapterData($this->playerId);
        $data->createDB($chapterId);
        return $data;
    }

    /**
     * 获取技巧教学章节下已开通的全部关卡
     * @param int $chapterId
     * @return array levelId=>levelData
     */
    public function getAllTeachingSkillLevelData(int $chapterId): array
    {
        $this->getInitPlayerConfig();
        $levelList = $this->initPlayerConfig[TemplateInitPlayer::TeachingSkillLevel][$chapterId] ?? array();
        $arr = array();
        foreach ($levelList as $levelId) {
            $levelData = $this->getLevelData($levelId);
            if ($levelData->levelId != 0) {
                $arr[$levelData->levelId] = $levelData;
            }
        }
        if (empty($arr)) {
            //开启全部关卡
            foreach ($levelList as $levelId) {
                $levelData = $this->createLevel($levelId);
                if ($levelData->levelId != 0) {
                    $arr[$levelData->levelId] = $levelData;
                }
            }
        }
        return $arr;
    }

    //更新技巧教学等级
    public function updateTeachingSkillLv(int $chapterId)
    {
        $drivingLicenseData = new DrivingLicenseData($this->playerId);
        $drivingLicenseData->searchDB();
        $drivingLicenseData->teachingSkillLv = $chapterId;
        $drivingLicenseData->updateDB();
        $this->sendTeachingSkillLvMessage($drivingLicenseData);
    }

    public function sendTeachingSkillLvMessage(DrivingLicenseData $drivingLicenseData = null)
    {
        if (is_null($drivingLicenseData)) {
            $drivingLicenseData = new DrivingLicenseData($this->playerId);
            $drivingLicenseData->searchDB();
        }
        $sendMessage = new GCTeachingSkill();
        $sendMessage->setTeachingSkillLv($drivingLicenseData->teachingSkillLv);
        SendMessage::getInstance()->sendClient(PacketId::GC_TeachingSkill, $sendMessage);
    }

    /**
     * 行驶证相关
     */

    /**
     * 获取对应车已开通的全部关卡
     * @param int $carTplId
     * @return array levelId=>levelData
     */
    public function getAllPermitLevelData(int $carTplId): array
    {
        $this->getInitPlayerConfig();
        $levelList = $this->initPlayerConfig[TemplateInitPlayer::DrivingPermitLevel][$carTplId] ?? array();
        $arr = array();
        if (empty($levelList)) {
            return $arr;
        }
        foreach ($levelList as $levelId) {
            $levelData = $this->getLevelData($levelId);
            /**
             * @var LevelData $levelData
             */
            if ($levelData->levelId != 0) {
                $arr[$levelData->levelId] = $levelData;
            }
        }
        if (empty($arr)) {
            $levelOrder = $this->initPlayerConfig[TemplateInitPlayer::DrivingPermitLevelOrder][$carTplId] ?? array();
            if (isset($levelOrder[0])) {
                $levelData = $this->createLevel($levelOrder[0]);
                if ($levelData->levelId != 0) {
                    $arr[$levelData->levelId] = $levelData;
                }
            } else {
                LogMark::getInstance()->markDebug(
                    "[PveModel] not found car first Level",
                    array(
                        "carId" => $carTplId,
                        "config" => $levelOrder
                    )
                );
            }
        }
        return $arr;
    }

    //通关后,记录关卡完成数
    public function updateCompleteLevelNum(int $carId)
    {
        $drivingPermitData = new DrivingPermitData($this->playerId);
        $drivingPermitData->increaseCompleteLevelNum($carId);
    }

    public function getCompleteLevelNum(): array
    {
        return (new DrivingPermitData($this->playerId))->searchDB();
    }


    /**
     * 生涯相关
     */
    //初始生涯信息
    private function initCarrerLevel()
    {
        $this->getInitPlayerConfig();
        $chapterId = 1;
        $levelIds = $this->initPlayerConfig[TemplateInitPlayer::CareerLevel][$chapterId][0] ?? array();
        if (empty($levelIds)) {
            LogMark::getInstance()->markError(
                GameErrorCode::TEMPLATE_ID_NOT_FOUND,
                "[PveModel] not found career first level",
                $this->initPlayerConfig
            );
            return;
        }
        $levelStar = array();
        foreach ($levelIds as $levelId) {
            $this->createCareerLevel($levelId, true);
            $levelStar[$levelId] = 0;
        }
        $chapterData = new CareerChapterData($this->playerId, $chapterId);
        $chapterData->registerDB($levelStar);
    }

    //获取已解锁的最大章节
    public function getChapterId(): int
    {
        return (new CareerChapterData($this->playerId, 0))->getUnlockChapterId();
    }

    //获取已解锁的最大关卡
    public function getMaxLevelId(): int
    {
        $chapterData = $this->getCareerChapterData($this->getChapterId());
        $maxLevel = 0;
        foreach ($chapterData as $key => $value) {
            if (is_numeric($key) && (int)$key >= $maxLevel) {
                $maxLevel = (int)$key;
            }
        }
        return $maxLevel;
    }

    //解锁新章节
    public function createCareerChapter(int $chapterId)
    {
        $chapterData = new CareerChapterData($this->playerId, $chapterId);
        $chapterData->initChapterData();
        $chapterData->updateUnlockChapterId($chapterId);
    }

    //解锁新关卡
    public function createCareerLevel(int $levelId, bool $isRegister = false): CareerLevelData
    {
        $careerLevelData = new CareerLevelData($this->playerId);
        $careerLevelData->initLevel($levelId);
        if ($isRegister) {
            $careerLevelData->registerDB();
        } else {
            $careerLevelData->saveDB();
        }
        EventLog_Manager::getInstance()->updateUserAttr(array(EventLogType::LOG_KEY_CAREER_LEVEL_ID => $levelId));
        return $careerLevelData;
    }

    //获取生涯章节信息
    public function getCareerChapterData(int $chapterId): array
    {
        return (new CareerChapterData($this->playerId, $chapterId))->searchDB();
    }

    //获取生涯关卡
    public function getCareerLevelData(int $levelId): CareerLevelData
    {
        $data = new CareerLevelData($this->playerId);
        $data->searchDB($levelId);
        return $data;
    }

    //更新章节数据
    public function updateCareerChapterData(int $chapterId, array $data)
    {
        $chapterData = new CareerChapterData($this->playerId, $chapterId);
        $chapterData->updateDB($data);
    }

    //更新章节关卡星数
    public function updateCareerChapterLevelStar(int $chapterId, int $levelId, int $star)
    {
        $chapterData = new CareerChapterData($this->playerId, $chapterId);
        $chapterData->updateDB(
            array(
                $levelId => $star
            )
        );
    }

    //获取已解锁关卡获得全部星数
    public function getAllStarNum(int $chapterId): int
    {
        $star = 0;
        $chapterData = $this->getCareerChapterData($chapterId);
        foreach ($chapterData as $key => $value) {
            if (is_numeric($key)) {
                $star += (int)$value;
            }
        }
        return $star;
    }

    //发送通关信息
    public function sendCareerLeveleMessage(array $levelList)
    {
        $levelInfo = [];
        foreach ($levelList as $careerLevelData) {
            /**
             * @var CareerLevelData $careerLevelData
             */
            $gameLevel = new GameLevel();
            $gameLevel->setLevelId($careerLevelData->levelId);
            $gameLevel->setLevelStar($careerLevelData->starNum);
            $gameLevel->setLevelStatus($careerLevelData->status);
            $gameLevel->setBestTime($careerLevelData->bestTime);
            $target = array(
                $careerLevelData->target1Status,
                $careerLevelData->target2Status,
                $careerLevelData->target3Status,
            );
            $gameLevel->setTarget(implode("-", $target));
            $levelInfo[] = $gameLevel;
        }
        $levelFinish = new GCGameLevelFinishLevelData();
        $levelFinish->setCode(ClientErrorCode::CLIENT_SUCCESS);
        $levelFinish->setInfo($levelInfo);
        SendMessage::getInstance()->sendClient(PacketId::GC_GameLevelFinishLevelData, $levelFinish);
    }
}
