<?php

/**
 * AccountModel.php
 * 文件描述
 * Created On 2022/1/13
 * @author yuanb yuanbo0x@gmail.com
 */

namespace Game\Model;

use Framework\DB\Handler\PlayerDBHandler;
use Framework\Lib\Utils;
use Framework\Log\LogMark;
use Game\Constant\ConstTemplate\TemplateCreateRole;
use Game\Constant\DBTableDefine;
use Game\Constant\GameErrorCode;
use Game\Constant\TemplateDefine;
use Game\Data\AccountData;
use Game\Data\Activity\ScuffleData;
use Game\Data\MoneyData;
use Game\Data\ProficiencyData;
use Game\Logic\RankLogic;
use Game\Data\RoleExtData;

class AccountModel
{
    use RankLogic;
    use PlayerDBHandler;
    private AccountData $data;
    private RoleExtData $ext;
    private int $playerId;

    public const CLOTH_FEMALE = 0;
    public const CLOTH_MALE = 1;

    // 收藏地图与取消收藏
    public const CUSTOMIZE_SAVE_MAP = 1;
    public const CUSTOMIZE_CANCEL_MAP = 2;

    // 衣服
    private const CLOTH_MALE_KEY = 'ClothMale';
    private const CLOTH_FEMALE_KEY = 'ClothFemale';

    private const ID_KEY = 'Id';
    private const COIN_KEY = 'Coin';
    private const COUPONS_KEY = 'Coupons';
    private const DIAMOND_KEY = 'Diamond';
    private const SEASON_KEY = 'Season';    //赛季代币
    private const WAR_TOKEN_KEY = 'WarToken';
    private const GIRL_KEY = 'playerClothStatusData_girl';
    private const BOY_KEY = 'playerClothStatusData_boy';
    private const ROLE_ID_KEY = 'RoleId';
    private const NICK_NAME_KEY = 'NickName';
    private const DRIVING_CAR_ID_KEY = 'DrivingCarId';
    private const CUSTOMIZE_MAP_ID = 'CustomizeMapID';

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

    /**
     * @param int $playerID
     * @return AccountData|null
     */
    public function getAccountInfo(int $playerID = 0): ?AccountData {
        if($playerID == 0) {
            $this->data->playerId = $this->playerId;
        } else {
            $this->data->playerId = $playerID;
        }
        if (!$this->data->searchData()){
            return null;
        }
        return $this->data;
    }

    /**
     * @return int
     */
    public function getPlayerId(): int
    {
        return $this->playerId;
    }

    public function __construct()
    {
        $this->data = new AccountData();
        $this->ext = new RoleExtData();
    }

    public function getDBType(): int
    {
        return DBTableDefine::TABLE_ACCOUNT;
    }

    public function updateRoleExt($data): bool
    {
        $this->ext->playerId = $this->playerId;
        if (!$this->ext->updateRoleExt($data)){
            return false;
        }
        return true;
    }

    public function register($playerId, $account, $type, $password, $clientData)
    {
        $this->data->playerId = $playerId;
        $this->data->account = $account;
        $this->data->sessionId = "";
        $this->data->loginTime = 0;
        $this->data->createTime = Utils::getServerTimestamp();
        $this->data->packetIndex = 0;
        $this->data->packetCache = "";
        $this->data->roomID = AccountData::DB_ROOM_ID_DEFAULT;
        $this->data->roomCustomizeID = AccountData::DB_CUSTOMIZE_ROOM_ID_DEFAULT;
        $this->data->licenceNum = 0;
        $this->data->licenceDate = '';
        $this->data->customizeMapID = [];
        $this->data->accountType = $type;
        $this->data->password = $password;
        $this->data->passwordMD5 = md5($password);
        $this->data->clientData = $clientData;
        $this->data->banTime = 0;
        $this->data->prohibitionTime = 0;
        $this->data->unlockChapterId = 1;
        $this->data->createDB();
        $this->playerId =  $playerId ;
    }

    public function login($playerId)
    {
        // 更新排行榜时间
        $this->updateLoginRankTime();
        $this->data->playerId = $playerId;
        $this->data->loginTime = Utils::getServerTimestamp();
        $this->data->logout = 0;
        $this->data->saveLogin();
    }

    public function saveLoginSession($playerId, $sessionId) {
        $this->data->playerId = $playerId;
        $this->data->sessionId = $sessionId;
        $this->data->saveLoginSession();
    }

    public function search($playerId, &$result): bool
    {
        return $this->data->loadFromDB($playerId, $result);
    }

    /**
     * 查询Account属性值
     * @param string|array $key
     * @return false|mixed
     */
    public function getAccountAttr($key)
    {
        $this->data->playerId = $this->playerId;
        if (!$this->data->inQuery($result)){
            return false;
        }
        if (!empty($result)) {
            if (is_string($key)){
                return $result[$key] ?? false;
            }
            if (is_array($key)){
                $tmp = [];
                foreach ($key as $k){
                    $tmp[$k] = $result[$k] ?? "";
                }
                return $tmp;
            }
        }
        return false;
    }

    /**
     * @param int $step
     */
    public function setStep(int $step): void
    {
        $this->step = $step;
    }

    private function getRoleId()
    {
        if (!$this->data->popQueue(DBTableDefine::TABLE_COMMON_ROLES_ID, 0, 0, $result))
        {
            return false;
        }
        //todo 检查是否重复.增加一个roleId-player对应的common表
        return $result;
    }

    public function saveAccount($data): bool {
        $this->data->playerId = $this->playerId;
        return $this->data->saveAccountData($data);
    }

    public function saveAccountDataByPlayerId(int $playerId, array $data): bool
    {
        $accountData = new AccountData();
        $accountData->playerId = $playerId;
        return $accountData->saveAccountData($data);
    }

    public function roleRegister($modelID, $step, &$data): bool
    {
        $roleID = $this->getRoleId();
        if ($roleID === false) {
            return false;
        }
        $cfg = $this->getTitle(TemplateDefine::TYPE_CREATE_ROLE, $modelID);
        if(is_null($cfg)) {
            LogMark::getInstance()->markError(
                GameErrorCode::DATA_SEARCH_ERROR,
                'search create role cfg data error!', ['modelID' => $modelID]
            );
        }
        $data = [];
        $data[AccountData::DB_CLOTH_FEMALE] = json_encode(array_values($cfg[TemplateCreateRole::InitClothFemale]));
        $data[AccountData::DB_CLOTH_MALE] = json_encode(array_values($cfg[TemplateCreateRole::InitClothMale]));
        $data[AccountData::DB_STEP] = $step;
        $data[AccountData::DB_RoleId] = $roleID;
        $data[AccountData::DB_LEVEL] = 1;   //初始1级
        $data[AccountData::DB_EXP] = 0;
        $data[AccountData::DB_ROLE_MODEL_ID] = $modelID;
        $data[AccountData::DB_SKIN_COLOR] = $cfg[TemplateCreateRole::SkinColor];
        $data[AccountData::DB_GENDER] = $cfg[TemplateCreateRole::Gender];
        $this->ext->initRoleExtData($data);

        return $this->data->saveAccountData($data);
    }

    public function saveDress($sex, $cloth, bool $isRank = true):bool
    {
        $this->data->playerId = $this->playerId;

        if(self::CLOTH_FEMALE == $sex) {
            $this->data->clothFemale = $cloth;
            $this->data->gender = $sex;
            if(!$this->data->saveFemaleDress()) {
                return false;
            }
        }

        if (self::CLOTH_MALE == $sex) {
            $this->data->clothMale = $cloth;
            $this->data->gender = $sex;
            if(!$this->data->saveMaleDress()) {
                return false;
            }
        }

        // 更新排行榜个人信息 change rank info table
        if($isRank) {
            $this->syncMineRankInfo();
        }

        return true;
    }

    /***
     * @return array
     * 获取校验数据,键名升序
     */
    public function getSignData():array
    {
        $retData = array();
        if ($this->search($this->playerId, $data)) {
            //取出需要校验的字段
            $retData[self::ID_KEY] = $this->playerId;
            $retData[self::COIN_KEY] = (int)($data[MoneyData::GOLD] ?? 0);
            $retData[self::COUPONS_KEY] = (int)($data[MoneyData::TICKETS] ?? 0);
            $retData[self::DIAMOND_KEY] = (int)($data[MoneyData::DIAMOND] ?? 0);
            $retData[self::SEASON_KEY] = (int)($data[MoneyData::SEASON] ?? 0);
            $retData[self::WAR_TOKEN_KEY] = (int)($data[MoneyData::ZL] ?? 0);

            $retData[AccountData::DB_ACCOUNT_TYPE] = (int)($data[AccountData::DB_ACCOUNT_TYPE] ?? AccountData::PLAYER_GM);
            $retData[AccountData::DB_CREATE_TIME] = (int)($data[AccountData::DB_CREATE_TIME] ?? 0);
            $retData[AccountData::DB_LICENCE_DATE] = $data[AccountData::DB_LICENCE_DATE] ?? "";
            $retData[AccountData::DB_LICENCE_NUM] = (int)($data[AccountData::DB_LICENCE_NUM] ?? 0);
            if(isset($data[AccountData::DB_CUSTOMIZE_ROOM_SAVE_MAP])) {
                $retData[self::CUSTOMIZE_MAP_ID] = json_decode($data[AccountData::DB_CUSTOMIZE_ROOM_SAVE_MAP], true);
            } else {
                $retData[self::CUSTOMIZE_MAP_ID] = json_decode("{}", true);
            }

            $femaleClothJsonStr = $data[AccountData::DB_CLOTH_FEMALE] ?? "";
            $maleClothJsonStr = $data[AccountData::DB_CLOTH_MALE] ?? "";

            $retData[AccountData::DB_GENDER] = (int)($data[AccountData::DB_GENDER] ?? 0);
            $retData[AccountData::DB_ROLE_MODEL_ID] = (int)($data[AccountData::DB_ROLE_MODEL_ID] ?? 0);
            $retData[AccountData::DB_PROHIBITION_TIME] = (int)($data[AccountData::DB_PROHIBITION_TIME] ?? 0);
            //检查是否为json
            $femaleCloth = array();
            if (Utils::IsJson($femaleClothJsonStr)) {
                $femaleCloth = json_decode($femaleClothJsonStr, true);
            }

            $retData[self::GIRL_KEY] = $femaleCloth;
            $maleCloth = array();
            if (Utils::IsJson($maleClothJsonStr)) {
                $maleCloth = json_decode($maleClothJsonStr, true);
            }
            $retData[self::BOY_KEY] = $maleCloth;
            $retData[self::ROLE_ID_KEY] = (int)($data[AccountData::DB_RoleId] ?? 0);
            $retData[self::NICK_NAME_KEY] = $data[AccountData::DB_NICK_NAME] ?? "";
            $retData[self::DRIVING_CAR_ID_KEY] = (int)($data[AccountData::DB_DEFAULT_CAR] ?? 0);
            //大乱斗积分
            $retData[ScuffleData::SCUFFLE_SCORE] = (int)($data[ScuffleData::SCUFFLE_SCORE] ?? 0);
            $retData[ScuffleData::SCUFFLE_ROLL_POINT] = (int)($data[ScuffleData::SCUFFLE_ROLL_POINT] ?? 0);
            //等级
            $retData[AccountData::DB_LEVEL] = (int)($data[AccountData::DB_LEVEL]);
            $retData[AccountData::DB_EXP] = (int)($data[AccountData::DB_EXP] ?? 0);
            //肤色
            $retData[AccountData::DB_SKIN_COLOR] = (int)($data[AccountData::DB_SKIN_COLOR] ?? 1);
            //熟练度
            $retData[ProficiencyData::PROFICIENCY_LV] = (int)($data[ProficiencyData::PROFICIENCY_LV] ?? 1);
            $retData[ProficiencyData::PROFICIENCY_REWARD] = json_decode($data[ProficiencyData::PROFICIENCY_REWARD], true);
            $retData[ProficiencyData::PROFICIENCY_EXPERT_REWARD] = json_decode($data[ProficiencyData::PROFICIENCY_EXPERT_REWARD], true);
            $retData[ProficiencyData::PROFICIENCY_FLAG] = (bool)(int)$data[ProficiencyData::PROFICIENCY_FLAG];
            //增益buff
            $retData[AccountData::DB_BUFF_DOUBLE_GOLD] = (int)($data[AccountData::DB_BUFF_DOUBLE_GOLD] ?? 0);
            $retData[AccountData::DB_BUFF_DOUBLE_PROFICIENCY] = (int)($data[AccountData::DB_BUFF_DOUBLE_PROFICIENCY] ?? 0);
            $retData[AccountData::DB_BUFF_DOUBLE_EXP] = (int)($data[AccountData::DB_BUFF_DOUBLE_EXP] ?? 0);
        }
        return $retData;
    }

    public function savePacketCache(int $index, string $packet)
    {
        if ($this->playerId == 0) {
            return;
        }
        $this->data->playerId = $this->playerId;
        $this->data->packetIndex = $index;
        $this->data->packetCache = $packet;
        $this->data->savePacketCache();
    }

    public function searchAccount(&$result)
    {
        return $this->data->loadFromDB($this->playerId, $result);
    }

    // 更新玩家当前房间id
    public function savePlayerRoomID(int $roomID, $playerID = 0)
    {
        if ($playerID != 0) {
            $this->playerId = $playerID;
        }
        $this->data->playerId = $this->playerId;
        $this->data->roomID = $roomID;
        $this->data->saveRoomID();
    }

    // 更新玩家当前房间id
    public function savePlayerRoomCustomizeID(int $roomID, $playerID = 0)
    {
        if ($playerID != 0) {
            $this->playerId = $playerID;
        }
        $this->data->playerId = $this->playerId;
        $this->data->roomCustomizeID = $roomID;
        $this->data->saveRoomCustomizeID();
    }

    // 更新玩家当前车牌当日随机次数
    public function savePlayerLicenceNum(int $num, $playerID = 0)
    {
        if ($playerID != 0) {
            $this->playerId = $playerID;
        }
        $this->data->playerId = $this->playerId;
        $this->data->licenceNum = $num;
        $this->data->saveLicenceNum();
    }

    // 更新玩家当前车牌当日随机次数
    public function saveCustomizeMap(array $maps, $playerID = 0)
    {
        if ($playerID != 0) {
            $this->playerId = $playerID;
        }
        $this->data->playerId = $this->playerId;
        $this->data->customizeMapID = $maps;
        $this->data->saveCustomizeMapID();
    }

    // 更新玩家当前车牌随机时间
    public function savePlayerLicenceDate(string $date, $playerID = 0)
    {
        if ($playerID != 0) {
            $this->playerId = $playerID;
        }
        $this->data->playerId = $this->playerId;
        $this->data->licenceDate = $date;
        $this->data->saveLicenceDate();
    }

    // 更新玩家退出俱乐部时间
    public function saveClubExitDate(int $date, $playerID = 0)
    {
        if ($playerID != 0) {
            $this->playerId = $playerID;
        }
        $this->data->playerId = $this->playerId;
        $this->data->clubExitTime = $date;
        $this->data->saveClubExitTime();
    }

    //更新玩家登录天数
    public function updatePlayerLoginDay(int $loginNum, int $loginContinuousNum, int $loginTime = 0): bool
    {
        $data = array(
            AccountData::DB_LOGIN_NUM => $loginNum,
            AccountData::DB_LOGIN_CONTINUOUS_NUM => $loginContinuousNum,
        );
        if ($loginTime != 0) {
            $data[AccountData::DB_LOGIN_TIME] = $loginTime;
        }
        $this->data->playerId = $this->playerId;
        return $this->data->saveAccountData($data);
    }

    //todo 增加车辆总性能分
    //更新车辆总性能分
    public function updateCarsPerformanceScore($score): bool
    {
        $this->data->playerId = $this->playerId;
        return $this->data->increaseAccountData(AccountData::DB_CARS_PERFORMANCE_SCORE, $score);
    }

    //account数值增加
    public function increaseAccountValue(string $key, int $value): int
    {
        $this->data->playerId = $this->playerId;
        $ret = 0;
        $this->data->increaseAccountDataValue($key, $value, $ret);
        return $ret;
    }
}
