<?php
/**
 * 房间逻辑类
 */

namespace Game\Logic\RoomCustomize;

use Framework\Log\LogMark;
use Framework\MVC\ModelManager;
use Framework\DB\Handler\PlayerDBHandler;
use Game\Constant\ClientErrorCode;
use Game\Constant\ConstTemplate\TemplateCompetitionMode;
use Game\Constant\GameConstantDefine;
use Game\Constant\GameErrorCode;
use Game\Constant\ModelTypeDefine;
use Game\Constant\TemplateDefine;
use Framework\Logic\TemplateHelp;
use Game\Data\AccountData;
use Game\Data\RoomCustomizeData;
use Game\Data\RoomData;
use Game\Logic\AccountLogic;
use Game\Model\RoomCustomizeModel;
use Game\Protobuf\GCRemoveCRoomByRoomID;
use Game\Protobuf\PacketId;

trait RoomLogic {

    use PlayerDBHandler;
    use TemplateHelp;
    use AccountLogic;
    public int $playerID;

    // 创建房间
    public function createRoom(int $mapID, int $modeType, string $roomName, string $password): bool {
        /**
         * @var RoomCustomizeModel $roomModel
         */
        $roomModel = ModelManager::getInstance()->getModel(ModelTypeDefine::ROOM_CUSTOMIZE);

        $mapCfg = $this->getTitle(TemplateDefine::TYPE_PVP_MAP, $mapID);
        if(is_null($mapCfg)) {
            logMark::getInstance()->markError(
                GameErrorCode::SEARCH_CONFIG_INFO_FAILED,
                '[logic] create customize room get map cfg by mapID error!',
                ['mapID' => $mapID]
            );
            $roomModel->GCJoinRoom(ClientErrorCode::ERROR_ROOM_MAP_NOT_EXIST);
            $roomModel->GCSendJoinRoom();
            return false;
        }

        $modeCfg = $this->getTitle(TemplateDefine::TYPE_COMPETITION_MODE, $modeType);
        if(is_null($modeCfg)) {
            logMark::getInstance()->markError(
                GameErrorCode::SEARCH_CONFIG_INFO_FAILED,
                '[logic] create room get mod cfg by modeType error!',
                ['modeType' => $modeType]
            );
            $roomModel->GCJoinRoom(ClientErrorCode::ERROR_ROOM_MODE_NOT_EXIST);
            $roomModel->GCSendJoinRoom();
            return false;
        }

        if(!$this->modeTypeIfOpen($modeCfg)) {
            logMark::getInstance()->markError(
                GameErrorCode::ROOM_MODE_TYPE_NOT_OPEN,
                '[logic] modeType not open error!',
                ['modeType' => $modeType]
            );
            $roomModel->GCJoinRoom(ClientErrorCode::ERROR_ROOM_MODE_TYPE_NOT_OPEN);
            $roomModel->GCSendJoinRoom();
            return false;
        }

        if(!$roomModel->createRoom($mapID, $modeType, $roomName, $password)) {
            LogMark::getInstance()->markError(
                GameErrorCode::DATA_CREATE_ERROR,
                '[logic] create customize room error!',
                ['mapID' => $mapID, 'modeType' => $modeType]
            );
            $roomModel->GCJoinRoom(ClientErrorCode::ERROR_CREATE_ROOM_FAILED);
            $roomModel->GCSendJoinRoom();
            return false;
        }
        $roomModel->GCSendJoinRoom();
        return true;
    }

    // 判断模式是否开启
    public function modeTypeIfOpen(array $modeCfg): bool {
        /**
         * @var RoomCustomizeModel $roomModel
         */
        $roomModel = ModelManager::getInstance()->getModel(ModelTypeDefine::ROOM_CUSTOMIZE);
        return $modeCfg[TemplateCompetitionMode::OpenIf] == $roomModel::MODE_OPEN;
    }

    // 通过roomID 加入房间中
    public function joinRoomByRoomID(int $roomID, string $password, int $isJoin, int $invitedPlayer = 0):bool {
        /**
         * @var RoomCustomizeModel $roomModel
         */
        $roomModel = ModelManager::getInstance()->getModel(ModelTypeDefine::ROOM_CUSTOMIZE);
        $this->playerID = $roomModel->playerId;
        $room = $roomModel->newRoom($roomID);
        if(!$room->searchRoomByRoomID()) {
            LogMark::getInstance()->markError(
                GameErrorCode::DATA_UPDATE_ERROR,
                '[logic] join customize room search  error!', (array)$room
            );
            $roomModel->GCJoinRoom(ClientErrorCode::ERROR_ROOM_NOT_EXIST);
            $roomModel->GCSendJoinRoom();
            return false;
        }
        // 私密不可进入
        if($isJoin === 0 && $room->roomState == $roomModel::ROOM_STATE_PRIVATE) {
            $roomModel->GCJoinRoom(ClientErrorCode::ERROR_ROOM_STATE_IS_PRIVATE);
            $roomModel->GCSendJoinRoom();
            return false;
        }

        if($room->playType == $roomModel::ROOM_GAME_MATCH_OR_PLAY) {
            LogMark::getInstance()->markInfo(
                '[model] join customize room playType is play or match!', (array)$room
            );
            $roomModel->GCJoinRoom(ClientErrorCode::ERROR_ROOM_IS_PLAY);
            $roomModel->GCSendJoinRoom();
            return false;
        }

        // 判断是否需要密码
        if($isJoin === 0 && $room->havePassword) {
            if(empty($password)) {
                $roomModel->GCJoinRoom(ClientErrorCode::ERROR_ROOM_INPUT_PASSWORD);
                $roomModel->GCSendJoinRoom();
                return false;
            }
            if($room->password != $password) {
                $roomModel->GCJoinRoom(ClientErrorCode::ERROR_ROOM_PASSWORD_FAILED);
                $roomModel->GCSendJoinRoom();
                return false;
            }
        }

        if(!$roomModel->playerJoinRoom($room, $invitedPlayer)) {
            $roomModel->GCSendJoinRoom();
            return false;
        }
        $roomModel->GCSendJoinRoom();
        $roomModel->GCSendAddJoinRoom();
        $this->upRoleStatus(GameConstantDefine::PLAYER_STATUS_ROOM, $roomModel->playerId);
        return true;
    }

    //  加入观战
    public function joinWatchByRoomID(int $roomID, string $password):bool {
        /**
         * @var RoomCustomizeModel $roomModel
         */
        $roomModel = ModelManager::getInstance()->getModel(ModelTypeDefine::ROOM_CUSTOMIZE);
        $this->playerID = $roomModel->playerId;
        $room = $roomModel->newRoom($roomID);
        if(!$room->searchRoomByRoomID()) {
            LogMark::getInstance()->markError(
                GameErrorCode::DATA_UPDATE_ERROR,
                '[logic] join customize room search  error!', (array)$room
            );
            $roomModel->GCJoinRoom(ClientErrorCode::ERROR_ROOM_NOT_EXIST);
            $roomModel->GCSendJoinRoom();
            return false;
        }

        // 私密不可进入
        if($room->roomState == $roomModel::ROOM_STATE_PRIVATE) {
            $roomModel->GCJoinRoom(ClientErrorCode::ERROR_ROOM_STATE_IS_PRIVATE);
            $roomModel->GCSendJoinRoom();
            return false;
        }

        // 判断是否需要密码
//        if($room->havePassword) {
//            if(empty($password)) {
//                $roomModel->GCJoinRoom(ClientErrorCode::ERROR_ROOM_INPUT_PASSWORD);
//                $roomModel->GCSendJoinRoom();
//                return false;
//            }
//            if($room->password != $password) {
//                $roomModel->GCJoinRoom(ClientErrorCode::ERROR_ROOM_PASSWORD_FAILED);
//                $roomModel->GCSendJoinRoom();
//                return false;
//            }
//        }

//        if($room->roomWatch >= RoomCustomizeModel::WATCH_MAX) {
//            LogMark::getInstance()->markInfo(
//                '[model] join customize room match but num is max!', (array)$room
//            );
//            $roomModel->GCJoinRoom(ClientErrorCode::ERROR_CUSTOMIZE_WATCH_MAX);
//            $roomModel->GCSendJoinRoom();
//            return false;
//        }

        if(!$roomModel->playerJoinWatchRoom($room)) {
            $roomModel->GCSendJoinRoom();
            return false;
        }
        $roomModel->GCSendJoinRoom();
        $roomModel->GCSendAddJoinRoom();
        $this->upRoleStatus(GameConstantDefine::PLAYER_STATUS_ROOM, $roomModel->playerId);
        return true;
    }

    // 房主踢人
    public function removePlayerByRoomID(int $roomID, int $playerID): bool {
        /**
         * @var RoomCustomizeModel $roomModel
         */
        $roomModel = ModelManager::getInstance()->getModel(ModelTypeDefine::ROOM_CUSTOMIZE);
        $this->playerID = $roomModel->playerId;
        $room = $roomModel->newRoom($roomID);
        $oldRoom = $roomModel->newRoom($roomID);
        $oldRoom->searchRoomByRoomID();

        if(!$room->searchRoomByRoomID()) {
            LogMark::getInstance()->markError(
                GameErrorCode::DATA_UPDATE_ERROR,
                '[logic] remove player search customize room  error!', (array)$room
            );
            $roomModel->GCRemovePlayer(ClientErrorCode::ERROR_ROOM_NOT_EXIST);
            $roomModel->GCSendRemovePlayer();
            return false;
        }

        $playerList = $room->playerInfo;

        array_multisort(array_column($playerList, RoomData::JOIN_TIME), SORT_ASC, $playerList);
        if($playerList[0][RoomData::PLAYER_ID] != $this->playerID) {
            $roomModel->GCRemovePlayer(ClientErrorCode::ERROR_ROOM_NOT_OWNER_IS_CHANGE);
            $roomModel->GCSendRemovePlayer();
            return false;
        }

        if(!$roomModel->removeRoomPlayer($room, $playerID)) {
            $roomModel->GCSendRemovePlayer();
            return false;
        }

        $roomModel->GCSendRemovePlayer();
        $room->searchRoomByRoomID();
        $roomModel->GCSendAddRemovePlayer($oldRoom->playerInfo);
        $this->upRoleStatus(GameConstantDefine::PLAYER_STATUS_ONLINE, $playerID);
        return true;
    }

    // 房主踢出所有玩家
    public function RemoveRoomAllPlayer(int $roomID): bool {
        /**
         * @var RoomCustomizeModel $roomModel
         */
        $roomModel = ModelManager::getInstance()->getModel(ModelTypeDefine::ROOM_CUSTOMIZE);
        $this->playerID = $roomModel->playerId;
        $room = $roomModel->newRoom($roomID);
        if(!$room->searchRoomByRoomID()) {
            LogMark::getInstance()->markError(
                GameErrorCode::DATA_UPDATE_ERROR,
                '[logic] exit room search customize room info error!', (array)$room
            );
            return false;
        }
        $sendMsg = new GCRemoveCRoomByRoomID();
        $sendMsg->setCode(0);
        foreach($room->playerInfo as $player) {
            $this->addPacket(PacketId::GC_RemoveCRoomByRoomID, $sendMsg, $player[RoomCustomizeData::PLAYER_ID]);
            $this->exitRoom($roomID, $player[RoomCustomizeData::PLAYER_ID]);
        }
        return true;
    }

    // 退出房间
    public function exitRoom(int $roomID, int $playerID = 0): bool {
        /**
         * @var RoomCustomizeModel $roomModel
         */
        $roomModel = ModelManager::getInstance()->getModel(ModelTypeDefine::ROOM_CUSTOMIZE);
        $this->playerID = $roomModel->playerId;
        $room = $roomModel->newRoom($roomID);
        if(!$room->searchRoomByRoomID()) {
            LogMark::getInstance()->markError(
                GameErrorCode::DATA_UPDATE_ERROR,
                '[logic] exit room search customize room info error!', (array)$room
            );
            $roomModel->GCExitRoom(ClientErrorCode::ERROR_ROOM_NOT_EXIST, $roomID);
            $roomModel->GCSendExitRoom();
            return false;
        }

        if(!$roomModel->exitRoom($room, $playerID)) {
            LogMark::getInstance()->markError(
                GameErrorCode::DATA_UPDATE_ERROR,
                '[logic] exit room  error!', (array)$room
            );
            $roomModel->GCSendExitRoom();
            return false;
        }
        $this->upRoleStatus(GameConstantDefine::PLAYER_STATUS_ONLINE, $roomModel->playerId);
        return true;
    }

    // 查找房间
    public function getCustomizeList(int $page): bool {
        /**
         * @var RoomCustomizeModel $roomModel
         */
        $roomModel = ModelManager::getInstance()->getModel(ModelTypeDefine::ROOM_CUSTOMIZE);
        if(!$roomModel->getRoomListByPage($page)) {
            LogMark::getInstance()->markError(
                GameErrorCode::DATA_SEARCH_ERROR,
                '[logic] get customize room list error!', ['page' => $page]
            );
            $roomModel->GCSendExitRoom();
            return false;
        }
        return true;
    }

    // 获取所有超时的房间列表
    public function cliGetTimeOutRoomList(&$ret): bool
    {
        /**
         * @var RoomCustomizeModel $roomModel
         */
        ModelManager::getInstance()->setPlayerId(0);
        $roomModel = ModelManager::getInstance()->getModel(ModelTypeDefine::ROOM_CUSTOMIZE);
        return $roomModel->getCheckRoomByScore($ret);
    }

    // 通过roomID 获取room信息
    public function cliGetRoomInfoByRoomID(int $roomID): ?RoomData {
        $room = new RoomCustomizeData($roomID);
        if(!$room->searchRoomByRoomID()) {
            LogMark::getInstance()->markError(
                GameErrorCode::DATA_SEARCH_ERROR,
                '[RoomLogic] cli search customize room info by room id error!', (array)$room
            );
            return null;
        }
        return $room;
    }

    // CLI 检测离线退出房间
    public function cliCheckOffLineExitRoom($roomID, int $playerID):bool {
        // 检测玩家是否在房间内
        $oldRoomID = $this->searchPlayerInfo($playerID)[AccountData::DB_ROOM_CUSTOMIZE_ID];
        /**
         * @var RoomCustomizeModel $roomModel
         */
        ModelManager::getInstance()->setPlayerId(0);
        $roomModel = ModelManager::getInstance()->getModel(ModelTypeDefine::ROOM_CUSTOMIZE);

        $room = $roomModel->checkPlayerInRoom($roomID);
        if(!is_null($room)) {
            if(!$roomModel->exitRoom($room, $playerID)) {
                LogMark::getInstance()->markError(
                    GameErrorCode::DATA_UPDATE_ERROR,
                    '[roomModel] cli check exit old customize room error!', (array)$room
                );
            }
            // 重置roomID
            $this->savePlayerRoomCustomizeID(AccountData::DB_CUSTOMIZE_ROOM_ID_DEFAULT, $playerID);
        }

        if($roomID != $oldRoomID) {
            $oldRoom = $roomModel->checkPlayerInRoom($oldRoomID);
            if(!is_null($oldRoom)) {
                if(!$roomModel->exitRoom($oldRoom, $playerID)) {
                    LogMark::getInstance()->markError(
                        GameErrorCode::DATA_UPDATE_ERROR,
                        '[roomModel] cli check exit old customize room error!', (array)$oldRoom
                    );
                }
                // 重置roomID
                $this->savePlayerRoomCustomizeID(AccountData::DB_CUSTOMIZE_ROOM_ID_DEFAULT, $playerID);
            }
        }
        return true;
    }

}