<?php
namespace Plugin\RenameCharacter;

class RenameCharacter {
    private $_modulesPath='modules';
    private $_cost=0;
    private $_configId=0;
    private $_newNameMinLen=3;
    private $_newNameMaxLen=10;
    private $_userid;
    private $_username;
    private $_character;
    private $_newName;
    private $_realm;
    private $_usercpmenu=array(
        array('active'=>true,'type'=>'internal','phrase'=>'renamecharacter_title','link'=>'usercp/renamecharacter','icon'=>'usercp_default.png','visibility'=>'user','newtab'=>false,'order'=>145)
    );

    public function __construct() {
        $this->_realm=class_exists('NexoraRealm') ? \NexoraRealm::active() : null;
        $path=self::configPath($this->_realm);
        if(!is_file($path)) throw new \Exception(lang('renamecharacter_error_2'));
        $xml=simplexml_load_file($path);
        if(!$xml) throw new \Exception(lang('renamecharacter_error_2'));
        $this->_cost=(int)$xml->rename_cost;
        $this->_configId=(int)$xml->config_id;
        $this->_newNameMinLen=max(1,(int)$xml->min_len);
        $this->_newNameMaxLen=max($this->_newNameMinLen,(int)$xml->max_len);
    }

    public static function configPath($realm=null) {
        if(class_exists('NexoraRealm')) {
            try {
                $realm=\NexoraRealm::validate($realm===null ? \NexoraRealm::active() : $realm);
                $realmPath=__PATH_RENAMECHARACTER_ROOT__.'config.'.$realm.'.xml';
                if(is_file($realmPath)) return $realmPath;
            } catch(\Throwable $e) {}
        }
        return __PATH_RENAMECHARACTER_ROOT__.'config.xml';
    }

    public function loadModule($module) {
        if(!\Validator::Alpha($module)) throw new \Exception(lang('renamecharacter_error_3'));
        $path=__PATH_RENAMECHARACTER_ROOT__.$this->_modulesPath.'/'.$module.'.php';
        if(!is_file($path)) throw new \Exception(lang('renamecharacter_error_3'));
        include $path;
    }
    public function setUserid($userid){$this->_userid=$userid;}
    public function setUsername($username){if(!\Validator::UsernameLength($username)) throw new \Exception(lang('renamecharacter_error_10')); $this->_username=$username;}
    public function setCharacter($character){if(!\Validator::AlphaNumeric($character)) throw new \Exception(lang('renamecharacter_error_6')); $this->_character=$character;}
    public function setNewCharacterName($name){$name=trim((string)$name); if(!\Validator::AlphaNumeric($name)) throw new \Exception(lang('renamecharacter_error_14')); $this->_newName=$name;}
    public function getCost(){return $this->_cost;}
    public function getMinLen(){return $this->_newNameMinLen;}
    public function getMaxLen(){return $this->_newNameMaxLen;}
    public function getRealm(){return $this->_realm;}

    public function getAccountCharacterList() {
        if(!check_value($this->_username)) throw new \Exception(lang('renamecharacter_error_4'));
        $list=(new \Character())->AccountCharacter($this->_username);
        if(!is_array($list) || count($list)<1) throw new \Exception(lang('renamecharacter_error_5'));
        return $list;
    }

    public function changeName() {
        if($this->_configId===0) throw new \Exception(lang('renamecharacter_error_15'));
        if(!check_value($this->_userid)||!check_value($this->_username)||!check_value($this->_character)||!check_value($this->_newName)) throw new \Exception(lang('renamecharacter_error_7'));
        if(!$this->_checkLength($this->_newName)) throw new \Exception(lang('renamecharacter_error_8'));
        if(strcasecmp($this->_character,$this->_newName)===0) throw new \Exception(lang('renamecharacter_error_16'));

        $accountInfo=(new \Account())->accountInformation($this->_userid);
        if(!is_array($accountInfo)) throw new \Exception(lang('renamecharacter_error_11'));
        if((new \Account())->accountOnline($this->_username)) throw new \Exception(lang('renamecharacter_error_12'));

        $creditSystem=new \CreditSystem();
        $creditSystem->setConfigId($this->_configId);
        $configInfo=$creditSystem->showConfigs(true);
        switch($configInfo['config_user_col_id']) {
            case 'userid': $identifier=$accountInfo[_CLMN_MEMBID_]; break;
            case 'username': $identifier=$accountInfo[_CLMN_USERNM_]; break;
            case 'email': $identifier=$accountInfo[_CLMN_EMAIL_]; break;
            case 'character': $identifier=$this->_character; break;
            default: throw new \Exception(lang('renamecharacter_error_11'));
        }

        $economy=new \NexoraEconomy($this->_realm);
        $result=$economy->renameCharacter($this->_configId,$identifier,$this->_username,$this->_character,$this->_newName,$this->_cost);
        $this->invalidateProfileCache($this->_character,$this->_newName);
        redirect(1,'usercp/renamecharacter/success/1/');
        return $result;
    }

    public static function issueRenameToken() {
        if(session_status()!==PHP_SESSION_ACTIVE) return '';
        $token=bin2hex(random_bytes(24));
        $_SESSION['nexora_rename_token']=$token;
        $_SESSION['nexora_rename_token_at']=time();
        return $token;
    }
    public static function consumeRenameToken($token) {
        if(session_status()!==PHP_SESSION_ACTIVE) return false;
        $expected=isset($_SESSION['nexora_rename_token'])?(string)$_SESSION['nexora_rename_token']:'';
        $at=isset($_SESSION['nexora_rename_token_at'])?(int)$_SESSION['nexora_rename_token_at']:0;
        unset($_SESSION['nexora_rename_token'],$_SESSION['nexora_rename_token_at']);
        return $expected!=='' && is_string($token) && hash_equals($expected,$token) && $at>0 && (time()-$at)<=900;
    }

    public function checkPluginUsercpLinks() {
        $cfg=loadConfig('usercp'); if(!is_array($cfg)) return;
        $links=array(); foreach($cfg as $row) if(isset($row['link'])) $links[]=$row['link'];
        foreach($this->_usercpmenu as $row) if(!in_array($row['link'],$links,true)) $cfg[]=$row;
        usort($cfg,function($a,$b){return ((int)$a['order'])<=>((int)$b['order']);});
        $json=json_encode($cfg,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
        if($json===false || file_put_contents(__PATH_CONFIGS__.'usercp.json',$json,LOCK_EX)===false) throw new \Exception('No se pudo actualizar el menu UserCP.');
    }

    private function _checkLength($name){$len=strlen($name); return $len>=$this->_newNameMinLen && $len<=$this->_newNameMaxLen;}
    private function invalidateProfileCache($old,$new) {
        if(!class_exists('NexoraRealm')) return;
        $dir=\NexoraRealm::profileCacheDirectory('players',$this->_realm);
        foreach(array($old,$new) as $name) {
            $path=$dir.strtolower((string)$name).'.cache';
            if(is_file($path)) @unlink($path);
        }
    }
}
