<?php

/**
 * Login.php
 * 文件描述
 * Created On 2021/12/29
 * @author yuanb yuanbo0x@gmail.com
 */

namespace Game\Controller\Login;

use Framework\Define\ErrorDefine;
use Framework\Lib\Utils;
use Framework\MVC\ControllerBase;
use Framework\MVC\ModelManager;
use Framework\Network\SendMessage;
use Game\Config\GameConfig;
use Game\Constant\ClientErrorCode;
use Game\Controller\Gm\Account;
use Game\Data\AccountData;
use Game\Logic\AccountLogic;
use Game\Protobuf\GCGetServerState;
use Game\Protobuf\GCSyncBanPlayer;
use Game\Protobuf\PacketId;
use Game\Protobuf\UserLoginRecv;
use Game\Protobuf\UserLoginSend;
use Tool\InitServer\Config;
use Game\Logic\CommonConstLogic;

class Login extends ControllerBase
{
    use AccountLogic;
    use CommonConstLogic;

    private UserLoginRecv $sendMessage;

    public function __construct()
    {
        $this->message = new UserLoginSend();
        $this->sendMessage = new UserLoginRecv();
    }

    public function run(): int
    {
        // 检测服务器状态
        if(!$this->checkServerState()) {
            return ErrorDefine::SUCCESS;
        }

        $account = $this->message->getAccount();
        $this->playerId = $this->searchPlayerIdByAccount($account);
        $sessionId = $this->makeSessionId();
        $isRegister = false;

        if ($this->playerId == 0) {
            $type = $this->message->getAccountType();
            $passWord = $this->message->getPassword();
            $deviceID = $this->message->getDeviceID();
            $isRegister = true;
            $this->playerId = $this->makePlayerId();
            $this->register($account, $this->playerId, $type, $passWord, $deviceID, $this->message->getClientData());
        }

        ModelManager::getInstance()->setPlayerId($this->playerId);
        $accountType = $this->getAccountProperty($this->playerId, AccountData::DB_ACCOUNT_TYPE);

        if(!$isRegister) {
            // 非注册封号
            if(!$this->checkBanPlayer()) {
                return ErrorDefine::SUCCESS;
            }
            // 游客校验密码
            if($accountType === AccountData::PLAYER_GUEST) {
                if(!$this->checkLoginPassword()) {
                    $this->sendLoginMsg(ClientErrorCode::LOGIN_PASSWORD_NOT_EQUAL_ERROR, $sessionId);
                    return ErrorDefine::SUCCESS;
                }
            }
        }

        $this->saveLoginSessoin($this->playerId, $sessionId);
        $clientData = $this->message->getClientData();
        $this->login($this->playerId, $isRegister, $clientData);
        $this->sendLoginMsg(ClientErrorCode::CLIENT_SUCCESS, $sessionId, $isRegister);
        return ErrorDefine::SUCCESS;
    }

    private function sendLoginMsg(int $code, string $sessionID, bool $isRegister =false) {
        $this->sendMessage->setCode($code);
        $this->sendMessage->setUserId($this->playerId);
        $this->sendMessage->setSessionId($sessionID);
        $this->sendMessage->setServerTime(Utils::getServerTimestamp());
        $this->sendMessage->setNoticeIP(GameConfig::getInstance()->NOTICE_SERVER_IP());
        $this->sendMessage->setNoticePort(GameConfig::getInstance()->NOTICE_SERVER_PORT());
        $this->sendMessage->setIsRegister($isRegister);
        SendMessage::getInstance()->sendClient(PacketId::User_Login_Recv, $this->sendMessage);
    }

    private function checkLoginPassword():bool {
        $passWord = $this->message->getPassword();
        $password = $this->getAccountProperty($this->playerId, AccountData::DB_PASSWORD_MD5);
        if(is_null($password)) {
            return false;
        }
        if($password != md5($passWord)) {
            return false;
        }
        return true;
    }

    private function checkServerState():bool {
        $msg = new GCGetServerState();
        $result = $this->getCommonConstData();
        if(!isset($result[Config::SERVER_STATE_KEY])) {
            $msg->setCode(ClientErrorCode::SERVER_STATE_SEARCH_NOT_FOUND_ERROR);
        } else {
            if($result[Config::SERVER_STATE_KEY] != Config::SERVER_TYPE_OPENING) {
                $time_str = GameConfig::getInstance()->OPEN_SERVER_TIME();
                $time_s = strtotime($time_str);
                $msg->setCode(ClientErrorCode::CLIENT_SUCCESS);
                $msg->setStartTime($time_s);
                $msg->setState((int)$result[Config::SERVER_STATE_KEY]);
            } else {
                return true;
            }
        }
        SendMessage::getInstance()->sendClient(PacketId::GC_GetServerState, $msg);
        return false;
    }

    // 检测封号
    private function checkBanPlayer():bool {
        $banTime = $this->getAccountProperty($this->playerId, AccountData::DB_BAN_TIME);
        // 没有被封号过
        if(is_null($banTime) || empty($banTime)) {
            return true;
        }
        $time = Utils::getServerTimestamp();
        // 已经解封
        if($time > $banTime) {
            return true;
        }
        $msg = new GCSyncBanPlayer();
        $msg->setCode(ClientErrorCode::CLIENT_SUCCESS);
        $msg->setTime($banTime);
        SendMessage::getInstance()->sendClient(PacketId::GC_SyncBanPlayer, $msg);
        return false;
    }

}
