<?php

/**
 * 任务基础管理
 */

namespace Game\Model\Task\Manager;

use Framework\Log\LogMark;
use Framework\Network\SendMessage;
use Framework\Logic\PacketCacheLogic;
use Framework\Logic\TemplateHelp;
use Game\Constant\ConstTemplate\TemplateTask;
use Game\Constant\GameErrorCode;
use Game\Constant\TemplateDefine;
use Game\Data\AccountData;
use Game\Data\TaskData;
use Game\Logic\EventConditionLogic;
use Game\Logic\ItemLogic;
use Game\Logic\Task\TaskEventLogic;
use Game\Operation\EventLog\CompleteTaskLog;
use Game\Operation\EventLog\EventLog_Manager;
use Game\Operation\EventLog\EventLogType;
use Game\Protobuf\GCTaskList;
use Game\Protobuf\PacketId;
use Game\Protobuf\Task;


class TaskMangerModelBase
{
    use TemplateHelp;
    use TaskEventLogic;
    use EventConditionLogic;
    use PacketCacheLogic;
    use ItemLogic;

    protected int $playerId;
    protected bool $isRegister = false;     //初始创建用户,批量创建任务用
    private array $pipeTempCreateTaskData  = array();   //批量创建时,存储任务id=>TaskData

    protected array $itemReward = array();
    protected int $numReward = 0; //特殊奖励--活跃度,战令经验
    protected int $expReward = 0;   //增加玩家经验
    protected array $changeTaskList = array();  //变化的任务,发消息用 taskId=>taskData

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

    //设置为初始创建用户
    public function setIsRegister()
    {
        $this->isRegister = true;
    }

    public function getIsRegister(): bool
    {
        return $this->isRegister;
    }

    public function getPipeTempTaskList(): array
    {
        return $this->pipeTempCreateTaskData;
    }

    public function clearPipeTempTaskList()
    {
        $this->pipeTempCreateTaskData = array();
    }

    //创建任务
    public function createTask(int $taskId, array $param = array()): bool
    {
        $taskConfig = $this->getTaskConfig($taskId);
        if (is_null($taskConfig)) {
            return false;
        }
        $taskData = new TaskData($this->playerId);
        if ($this->isRegister) {
            $taskData->setIsRegister();
        }
        $taskData->initTask($taskId, $taskConfig, $param);
        if (false == $this->initTaskLogic($taskData, $param, $this->isRegister)) {
            LogMark::getInstance()->markDebug(
                "[TaskMangerModelBase]create Task,init Logic fail,",
                array("taskId" => $taskId)

            );
            return false;
        }
        if ($this->isRegister) {
            $this->pipeTempCreateTaskData[$taskId] = $taskData;
        }
        return $taskData->create();
    }
    // 周任务创建逻辑
    public function createWeekTask(int $taskId, array $param = array()): bool
    {
        $taskConfig = $this->getTaskConfig($taskId);
        if (is_null($taskConfig)) {
            return false;
        }
        $taskData = new TaskData($this->playerId);
        if ($this->isRegister) {
            $taskData->setIsRegister();
        }
        $taskData->initTask($taskId, $taskConfig, $param);
        // 创建周任务的 event
        if (false == $this->changeWeekLoginTaskLogic($taskData, $param, $this->isRegister)) {
            LogMark::getInstance()->markDebug(
                "[TaskMangerModelBase]update week Task event,init Logic fail,",
                array("taskId" => $taskId)

            );
            return false;
        }
        return $taskData->create();
    }

    // 周任务事件更新
    public function updateWeekTask(int $taskId, array $param = array()): bool
    {
        $taskConfig = $this->getTaskConfig($taskId);
        if (is_null($taskConfig)) {
            return false;
        }
        $taskData = new TaskData($this->playerId);
        $taskData->initTask($taskId, $taskConfig, $param);
        if (false == $this->changeWeekTaskLogic($taskData, $param)) {
            LogMark::getInstance()->markDebug(
                "[TaskMangerModelBase]update week Task event,init Logic fail,",
                array("taskId" => $taskId)

            );
            return false;
        }
        return true;
    }

    //查询任务
    public function getTask(int $taskId): ?TaskData
    {
        $taskData = new TaskData($this->playerId);
        if (false == $taskData->getTask($taskId)) {
            LogMark::getInstance()->markError(
                GameErrorCode::TASK_NOT_FOUND_IN_DB,
                "[TaskMangerModelBase] task not found in db",
                array(
                    "taskId" => $taskId
                )
            );
            return null;
        }
        if ($taskData->taskId == 0) {
            return null;
        }
        return $taskData;
    }

    //查询任务是否存在 不打印日志
    public function getTaskHave(int $taskId): ?TaskData
    {
        $taskData = new TaskData($this->playerId);
        if (false == $taskData->getTask($taskId)) {
            return null;
        }
        if ($taskData->taskId == 0) {
            return null;
        }
        return $taskData;
    }

    //更新任务
    public function updateTask(TaskData $taskData): bool
    {
        //成长任务(原主线任务) 完成检查
        $this->checkAcceptNextMainTask($taskData);
        return $taskData->updateTask();
    }

    //完成任务
    public function completeTask(TaskData $taskData)
    {
        //修改状态
        $taskData->status = TaskData::STATUS_OVER;
        $taskData->updateTask();
        //加奖励
        $this->addTaskReward($taskData->taskConfig);
        //记录变化
        $this->addChangeTask($taskData);
        $this->setLogTaskId($taskData->taskId);
        //记录打点日志
        $log = EventLog_Manager::getInstance()->getEventLog(EventLogType::CompleteTask);
        if (is_null($log)) {
            return;
        }
        /**
         * @var CompleteTaskLog $log
         */
        $log->taskId = $taskData->taskId;
        $log->taskType = $taskData->taskConfig[TemplateTask::TaskType];
        $log->reward = $taskData->taskConfig[TemplateTask::Reward];
        $log->carId = (int)$this->getAccountProperty($this->playerId, AccountData::DB_DEFAULT_CAT_TPL, 0);
        $log->markLog();
    }

    //删除任务
    public function delTask(int $taskId): bool
    {
        //检查任务是否完成
        $taskData = $this->getTask($taskId);
        if (is_null($taskData)) {
            return true;
        }
        /**
         * @var TaskData $taskData
         */
        if (!is_null($taskData->taskConfig) && $taskData->status == TaskData::STATUS_DOING) {
            //移除事件
            $this->removeEventByTaskId($taskData);
        }
        //删除数据
        return $taskData->delTask($taskId);
    }

    //重置任务
    public function resetTask(int $taskId, array $param = array()): bool
    {
        $taskData = $this->getTask($taskId);
        if (is_null($taskData)) {
            LogMark::getInstance()->markError(
                GameErrorCode::TASK_ID_NOT_FOUND,
                "[TaskMangerModelBase] reset task,but task not found",
                array(
                    "taskId" => $taskId
                )
            );
            return false;
        }
        //重置进度和状态
        $taskData->reset();
        if (false == $this->initTaskLogic($taskData, $param)) {
            LogMark::getInstance()->markDebug(
                "[TaskMangerModelBase]reset Task,init Logic fail,",
                array("taskId" => $taskId)

            );
            return false;
        }
        return $taskData->updateTask();
    }

    //重置任务
    public function resetWeekTask(int $taskId, array $param = array()): bool
    {
        $taskData = $this->getTask($taskId);
        if (is_null($taskData)) {
            LogMark::getInstance()->markError(
                GameErrorCode::TASK_ID_NOT_FOUND,
                "[TaskMangerModelBase] reset task,but task not found",
                array(
                    "taskId" => $taskId
                )
            );
            return false;
        }
        $taskData->reset();
        if (false == $this->changeWeekLoginTaskLogic($taskData, $param)) {
            LogMark::getInstance()->markDebug(
                "[TaskMangerModelBase]reset Task,init Logic fail,",
                array("taskId" => $taskId)

            );
            return false;
        }
        return $taskData->updateTask();
    }

    //触发任务
    public function trigger(array $taskIds, array $param, bool $isSend = true)
    {
        //查询任务
        foreach ($taskIds as $taskId) {
            $taskData = $this->getTask($taskId);
            if (is_null($taskData) || $taskData->taskId == 0) {
                continue;
            }
            $this->triggerTask($taskData, $param);
            if ($taskData->isChange) {
                $this->updateTask($taskData);
                $this->addChangeTask($taskData);
            }
        }
        if ($isSend) {
            $this->sendChangeTaskMessage();
        } else {
            $this->addChangeTaskMessageToPacket();
        }
    }

    public function addChangeTask(TaskData $taskData)
    {
        if ($taskData->isSync) {
            $this->changeTaskList[$taskData->taskId] = $taskData;
        }
    }

    public function clearChangeTask()
    {
        $this->changeTaskList = array();
    }

    public function getCompleteReward(): array
    {
        return array($this->itemReward, $this->numReward, $this->expReward);
    }

    //根据taskId加奖励
    public function addTaskRewardByTaskId(int $taskId)
    {
        $taskConfig = $this->getTaskConfig($taskId);
        if (is_null($taskConfig)) {
            //任务已删除 奖励不发放
            return;
        }
        $this->addTaskReward($taskConfig);
    }

    //加奖励道具
    private function addTaskReward(array $taskConfig)
    {
        $this->tidyRewardItem($taskConfig);
        //增加特殊道具
        $this->numReward += $taskConfig[TemplateTask::NumReward];
        $this->expReward += $taskConfig[TemplateTask::EXP];
    }

    //整理奖励道具
    private function tidyRewardItem(array $taskConfig)
    {
        foreach ($taskConfig[TemplateTask::Reward] as $itemId => $num) {
            isset($this->itemReward[$itemId]) ?
                $this->itemReward[$itemId] += $num :
                $this->itemReward[$itemId] = $num;
        }
    }

    //发送消息 任务变化
    public function sendChangeTaskMessage()
    {
        if (!empty($this->changeTaskList)) {
            /**
             * @var TaskData $taskData
             */
            $taskMessage = array();
            $completeTaskList = array();
            foreach ($this->changeTaskList as $taskId => $taskData) {
                if ($taskData->status == TaskData::STATUS_OVER) {
                    $completeTaskList[] = $taskId;
                } else {
                    $task = new Task();
                    $task->setTaskId($taskData->taskId);
                    $task->setStatus($taskData->status);
                    $task->setSchedule($taskData->schedule);
                    $taskMessage[] = $task;
                }
            }
            $sendMessage = new GCTaskList();
            $sendMessage->setTaskList($taskMessage);
            $sendMessage->setCompleteTaskList($completeTaskList);
            SendMessage::getInstance()->sendClient(PacketId::GC_TaskList, $sendMessage);
            $this->changeTaskList = array();
        }
    }

    //任务变化消息 加入缓存
    private function addChangeTaskMessageToPacket()
    {
        if (!empty($this->changeTaskList)) {
            /**
             * @var TaskData $taskData
             */
            $taskMessage = array();
            $completeTaskList = array();
            foreach ($this->changeTaskList as $taskId => $taskData) {
                if ($taskData->status == TaskData::STATUS_OVER) {
                    $completeTaskList[] = $taskId;
                } else {
                    $task = new Task();
                    $task->setTaskId($taskData->taskId);
                    $task->setStatus($taskData->status);
                    $task->setSchedule($taskData->schedule);
                    $taskMessage[] = $task;
                }
            }
            $sendMessage = new GCTaskList();
            $sendMessage->setTaskList($taskMessage);
            $sendMessage->setCompleteTaskList($completeTaskList);
            $this->addPacket(PacketId::GC_TaskList, $sendMessage);
            $this->changeTaskList = array();
        }
    }

    private function getTaskConfig(int $taskId): ?array
    {
        $taskConfig = $this->getTitle(TemplateDefine::TYPE_TASK, $taskId);
        if (is_null($taskConfig)) {
            LogMark::getInstance()->markError(
                GameErrorCode::TASK_ID_NOT_FOUND,
                "[taskData] taskId not found",
                array(
                    "taskId" => $taskId
                )
            );
        }
        return $taskConfig;
    }

    //成长任务(原主线任务) 状态变为完成后 接一下个任务
    private function checkAcceptNextMainTask(TaskData $taskData)
    {
        if ($taskData->taskConfig[TemplateTask::TaskType] != TemplateTask::TASK_TYPE_MAIN) {
            return;
        }
        if ($taskData->status == TaskData::STATUS_DONE) {
            $nextTaskId = $taskData->taskConfig[TemplateTask::NextTask];
            if ($nextTaskId == 0) {
                //没有后续任务
                return;
            }
            while ($nextTaskId != 0) {
                //循环检查,防止新创建的任务直接完成
                if (is_null($this->getTask($nextTaskId))) {
                    //创建下个任务
                    if ($this->createTask($nextTaskId)) {
                        $this->addChangeTask($this->getTask($nextTaskId));
                        $newTaskData = $this->getTask($nextTaskId);
                        if (is_null($newTaskData) || $newTaskData->status == TaskData::STATUS_DOING) {
                            break;
                        }
                        $nextTaskId = $newTaskData->taskConfig[TemplateTask::NextTask];
                    } else {
                        break;
                    }
                } else {
                    break;
                }
            }
        }
    }
}
