<?php

namespace support;

use app\model\User;
use app\model\UserRule;
use support\think\Db;

class Jwt
{
    protected static $instance = null;
    protected static $_error = '';
    protected static $_logined = false;
    protected static $_user = null;
    protected static $_token = '';
    //Token默认有效时长
    protected static $keeptime = 2592000;
    protected static $requestUri = '';
    protected static $rules = [];
    //默认配置
    protected static $config = [];
    protected static $options = [];
    protected static $disallowFields = [
        'password','trade_password','totp_secret',//安全信息
        'created_at','updated_at','loginfailure',//系统信息
        //'last_time','last_ip','join_time','join_ip',最近登录信息
        //'score',
        'level',
        
    ];
    /**
     * 注册用户
     *
     * @param string $username 用户名
     * @param string $password 密码
     * @param string $email    邮箱
     * @param string $mobile   手机号
     * @param array  $extend   扩展参数
     * @return boolean
     */
    public static function register($username, $password, $email = '', $mobile = '', $extend = []): array|bool
    {
        // 检测用户名、昵称、邮箱、手机号是否存在
        if (User::getByUsername($username)) {
            self::setError('Username already exist');
            return false;
        }
        if (User::getByNickname($username)) {
            self::setError('Nickname already exist');
            return false;
        }
        if ($email && User::getByEmail($email)) {
            self::setError('Email already exist');
            return false;
        }
        if ($mobile && User::getByMobile($mobile)) {
            self::setError('Mobile already exist');
            return false;
        }
        $request = request();
        if($request){
            $ip = getRealIp();
        }else{
            $ip = '127.0.0.1';
        }
        $time = time();

        $data = [
            'username' => $username,
            'password' => $password,
            'email'    => $email,
            'mobile'   => $mobile,
            'level'    => 1,
            'score'    => 0,
            'avatar'   => '',
        ];
        $params = array_merge($data, [
            //'nickname'  => preg_match("/^1[3-9]{1}\d{9}$/", $username) ? substr_replace($username, '****', 3, 4) : $username,
            'nickname'  => "wx_".Random::alnum(),
            //'salt'      => Random::alnum(),
            'join_time'  => $time,
            'join_ip'    => $ip,
            'last_time' => $time,
            'last_ip'   => $ip,
            'status'    => '1'
        ]);
        $region = Request()->post('region');
        if($region){
            $params['region'] = str_replace('+','',$region);
        }
        $params['password'] = \plugin\admin\app\common\Util::passwordHash($password);
        $params = array_merge($params, $extend); 

        //账号注册时需要开启事务,避免出现垃圾数据
        Db::startTrans();
        try {
            $user = User::create($params,[], true);
            /**             
             * @var User $user
             * */
            $user->role_id;
            $user = User::where('id',$user->id)->find();
            $user['client'] = \support\Jwt\JwtToken::TOKEN_CLIENT_WEB;
            if(Request()->client == 'win'){
                $user['client'] = \support\Jwt\JwtToken::TOKEN_CLIENT_PC;
                \support\Jwt\JwtToken::clear(\support\Jwt\JwtToken::TOKEN_CLIENT_PC);
            }
            $_token = \support\Jwt\JwtToken::generateToken($user->toArray());
            $user->token = $_token['access_token'];
            //注册成功的事件
            Hook("user.register_successed", $user);
            Db::commit();
            return self::getUserinfo($user);
        } catch (\Exception $e) {
            Db::rollback();
            self::setError($e->getMessage());
            return false;
        }
    }
    /**
     * 用户登录
     *
     * @param string $account  账号,用户名、邮箱、手机号
     * @param string $password 密码
     * @return boolean
     */
    public static function login($account, $password,$type=''): array|bool
    {
        if($type){
            $field = $type;
        }else{
            $field = strpos('@',$account)!==false ? 'email' : 'username';
        }
        /**             
         * @var User $user
         * */
        if($field=='mobile'){
            $region = Request()->post('region');
            $region = str_replace('+','',$region);
            $user = User::where($field , $account)->where('region',$region)->find();
        }else{
            $user = User::where($field , $account)->find();
        }
        if (!$user) {
            self::setError('Account is incorrect');
            return false;
        }

        if ($user->status != 1) {
            self::setError('Account is locked');
            return false;
        }
        //if ($user->username!='' && !\plugin\admin\app\common\Util::passwordVerify($password,$user->password)) {
        if (!\plugin\admin\app\common\Util::passwordVerify($password,$user->password)) {
            self::setError('Password is incorrect');
            return false;
        }

        //直接登录会员
        return self::direct($user->id);
    }

    /**
     * 退出
     *
     * @return boolean
     */
    public static function logout()
    {
        //退出成功的事件
        Hook("user.logout_successed");
        return true;
    }

    /**
     * 修改密码
     * @param string $newpassword       新密码
     * @param string $oldpassword       旧密码
     * @param bool   $ignoreoldpassword 忽略旧密码
     * @return boolean
     */
    public static function changepwd($newpassword, $oldpassword = '', $ignoreoldpassword = false)
    {
        if (!self::isLogin()) {
            self::setError('You are not logged in');
            return false;
        }
        $user = self::getUser();
        //判断旧密码是否正确
        if (!\plugin\admin\app\common\Util::passwordVerify($oldpassword,$user->password) || $ignoreoldpassword) {
            Db::startTrans();
            try {
                $salt = Random::alnum();
                User::where('id',$user->id)->save([
                    'loginfailure' => 0, 
                    'password' => \plugin\admin\app\common\Util::passwordHash($newpassword)
                ]);
                //修改密码成功的事件
                Hook("user.changepwd_successed", $user);
                Db::commit();
            } catch (\Exception $e) {
                Db::rollback();
                self::setError($e->getMessage());
                return false;
            }
            return true;
        } else {
            self::setError('Password is incorrect');
            return false;
        }
    }

    /**
     * 修改交易密码
     * @param string $newpassword       新密码
     * @param string $oldpassword       旧密码
     * @param bool   $ignoreoldpassword 忽略旧密码
     * @return boolean
     */
    public static function change_trade_pwd($newpassword, $oldpassword = '', $ignoreoldpassword = false)
    {
        $user = self::getUser();
        if (!self::isLogin()) {
            self::setError('You are not logged in');
            return false;
        }
        //判断旧密码是否正确
        if (!$user->trade_password || $ignoreoldpassword || \plugin\admin\app\common\Util::passwordVerify($oldpassword,$user->trade_password)) {
            Db::startTrans();
            try {
                $salt = Random::alnum();
                User::where('id',$user->id)->save(['trade_password' => \plugin\admin\app\common\Util::passwordHash($newpassword)]);
                //修改密码成功的事件
                Hook("user.change_trade_pwd_successed", $user);
                Db::commit();
            } catch (\Exception $e) {
                Db::rollback();
                self::setError($e->getMessage());
                return false;
            }
            return true;
        } else {
            self::setError('Old password is incorrect');
            return false;
        }
    }
    static function verify_trade_password($password){
        $user = self::getUser();
        if(is_null($user->trade_password)){
            throw new \Exception(__('Please set the trade password first'),200);
        }
        if (!\plugin\admin\app\common\Util::passwordVerify($password,$user->trade_password)) {
            throw new \Exception(__('Trade password is incorrect'),200);
        }
    }

    /**
     * 直接登录账号
     * @param int $user_id
     * @return boolean
     */
    public static function direct($user_id): array|bool
    {
        $user = User::where('id',$user_id)->find();
        if ($user) {
            Db::startTrans();
            try {
                $ip = getRealIp();
                $time = time();

                //记录本次登录的IP和时间
                $user->last_ip = $ip;
                $user->last_time = $time;
                //重置登录失败次数
                $user->loginfailure = 0;

                $user->save();
                Db::commit();
                $user['client'] = \support\Jwt\JwtToken::TOKEN_CLIENT_WEB;
                if(Request()->client == 'win'){
                    $user['client'] = \support\Jwt\JwtToken::TOKEN_CLIENT_PC;
                    //\support\Jwt\JwtToken::clear(\support\Jwt\JwtToken::TOKEN_CLIENT_PC);
                }
                $_user = $user->toArray();
                $_user = [
                    'id'        => $_user['id'],
                    'username'  => $_user['username'],
                    'client'    => $_user['client'],
                ];
                $_token = \support\Jwt\JwtToken::generateToken($_user);
                $user->token = $_token['access_token'];
                //登录成功的事件
                Hook("user.login_successed", $user);
                return self::getUserinfo($user);
            } catch (\Exception $e) {
                Db::rollback();
                self::setError($e->getMessage());
                return false;
            }
        } else {
            return false;
        }
    }

    /**
     * 检测是否是否有对应权限
     * @param string $path   控制器/方法
     * @param string $module 模块 默认为当前模块
     * @return boolean
     */
    public static function check($path = null, $module = null)
    {
        if (!self::isLogin()) {
            return false;
        }

        $ruleList = self::getRuleList();
        $rules = [];
        foreach ($ruleList as $k => $v) {
            $rules[] = $v['key'];
        }
        $url = ($module ? $module : request()->app) . '/' . (is_null($path) ? self::getRequestUri() : $path);
        $url = strtolower(str_replace('.', '/', $url));
        return in_array($url, $rules);
    }

    /**
     * 判断是否登录
     * @return boolean
     */
    public static function isLogin()
    {
        $user_id = \support\Jwt\JwtToken::getCurrentId();
        if ($user_id) {
            return true;
        }
        return false;
    }



    /**
     * 获取User模型
     * @return User
     */
    public static function getUser($user=null)
    {
        $user = $user ?  $user : \support\Jwt\JwtToken::getUser();
        return $user;
    }
    /**
     * 获取会员基本信息
     */
    public static function getUserinfo($user=null)
    {
        $data = self::getUser($user)->toArray();
        $disallowFields = self::getDisallowFields();
        $userinfo = array_diff_key($data, array_flip($disallowFields));
        $userinfo['has_trade_password'] = $data['trade_password'] ? true: false;
        return $userinfo;
    }

    /**
     * 获取会员组别规则列表
     * @return array|bool|\PDOStatement|string|\think\Collection
     */
    public static function getRuleList()
    {
        $user = self::getUser();
        $role_id = $user->role_id;
        if (!$role_id) {
            return [];
        }
        if (cache('group_rules_'.$role_id)) {
            return cache('group_rules_'.$role_id);
        }
        $rules = explode(',', $role_id);
        $rules = UserRule::where('status', 'normal')->where('id', 'in', $rules)->field('id,pid,key,title,type')->select();
        cache('group_rules_'.$role_id,$rules);
        return $rules;
    }

    /**
     * 获取当前请求的URI
     * @return string
     */
    public static function getRequestUri()
    {
        return self::$requestUri;
    }

    /**
     * 设置当前请求的URI
     * @param string $uri
     */
    public static function setRequestUri($uri)
    {
        self::$requestUri = $uri;
    }

    /**
     * 获取允许输出的字段
     * @return array
     */
    public static function getDisallowFields()
    {
        return self::$disallowFields;
    }

    /**
     * 设置允许输出的字段
     * @param array $fields
     */
    public static function setDisallowFields($fields)
    {
        self::$disallowFields = $fields;
    }

    /**
     * 删除一个指定会员
     * @param int $user_id 会员ID
     * @return boolean
     */
    public static function delete($user_id)
    {
        $user = User::where('id',$user_id)->find();
        if (!$user) {
            return false;
        }
        Db::startTrans();
        try {
            // 删除会员
            User::destroy($user_id);

            Hook("user.delete_successed", $user);
            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            self::setError($e->getMessage());
            return false;
        }
        return true;
    }

    /**
     * 获取密码加密后的字符串
     * @param string $password 密码
     * @param string $salt     密码盐
     * @return string
     */
    public function getEncryptPassword($password, $salt = '')
    {
        return md5(md5($password) . $salt);
    }

    /**
     * 检测当前控制器和方法是否匹配传递的数组
     *
     * @param array $arr 需要验证权限的数组
     * @return boolean
     */
    public static function match($arr = [])
    {
        $request = Request();
        $arr = is_array($arr) ? $arr : explode(',', $arr);
        if (!$arr) {
            return false;
        }
        $arr = array_map('strtolower', $arr);
        // 是否存在
        if (in_array(strtolower($request->action), $arr) || in_array('*', $arr)) {
            return true;
        }

        // 没找到匹配
        return false;
    }

    /**
     * 渲染用户数据
     * @param array  $datalist  二维数组
     * @param mixed  $fields    加载的字段列表
     * @param string $fieldkey  渲染的字段
     * @param string $renderkey 结果字段
     * @return array
     */
    public function render(&$datalist, $fields = [], $fieldkey = 'user_id', $renderkey = 'userinfo')
    {
        $fields = !$fields ? ['id', 'nickname', 'level', 'avatar'] : (is_array($fields) ? $fields : explode(',', $fields));
        $ids = [];
        foreach ($datalist as $k => $v) {
            if (!isset($v[$fieldkey])) {
                continue;
            }
            $ids[] = $v[$fieldkey];
        }
        $list = [];
        if ($ids) {
            if (!in_array('id', $fields)) {
                $fields[] = 'id';
            }
            $ids = array_unique($ids);
            $selectlist = User::where('id', 'in', $ids)->column($fields);
            foreach ($selectlist as $k => $v) {
                $list[$v['id']] = $v;
            }
        }
        foreach ($datalist as $k => &$v) {
            $v[$renderkey] = $list[$v[$fieldkey]] ?? null;
        }
        unset($v);
        return $datalist;
    }

    /**
     * 设置错误信息
     *
     * @param string $error 错误信息
     * @return void
     */
    public static function setError($error)
    {
        self::$_error = $error;
        abort($error);
    }

    /**
     * 获取错误信息
     * @return string
     */
    public static function getError()
    {
        return self::$_error ? __(self::$_error) : '';
    }
}
