<?php
/**
 * This file is part of workerman.
 *
 * Licensed under The MIT License
 * For full copyright and license information, please see the MIT-LICENSE.txt
 * Redistributions of files must retain the above copyright notice.
 *
 * @author walkor<walkor@workerman.net>
 * @copyright walkor<walkor@workerman.net>
 * @link http://www.workerman.net/
 * @license http://www.opensource.org/licenses/mit-license.php MIT License
 */

 namespace app\worker;
/**
 * 推送主逻辑
 * 主要是处理 onMessage onClose 
 */
use GatewayWorker\Lib\Gateway;
use app\worker\Application;
use think\facade\Config;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Parser;
use thans\jwt\provider\JWT\Lcobucci;
use utils\Aes;
use app\enterprise\model\User;

class Events
{
    // 使用TP框架
    public static function onWorkerStart()
    {
        $app = new Application;
        $app->initialize();
    }

    // 当有客户端连接时，将client_id返回，让mvc框架判断当前uid并执行绑定
    public static function onConnect($client_id)
    {
        Gateway::sendToClient($client_id, json_encode(array(
            'type'      => 'init',
            'client_id' => $client_id,
        )));
        self::onlineStatistics();
    }
    /**
    * 有消息时
    * @param int $client_id
    * @param mixed $message
    */
   public static function onMessage($client_id, $message)
   {
        // 客户端传递的是json数据
        $message_data = json_decode($message, true);
        if(!$message_data)
        {
            return ;
        }
        
        // 根据类型执行不同的业务
        switch($message_data['type'])
        {
            // 客户端回应服务端的心跳
            case 'pong':
                // 三次心跳后如果没有登录则断开连接
                $_SESSION['pong_times'] = ($_SESSION['pong_times'] ?? 0) + 1;
                $user_id=$_SESSION['user_id'] ?? '';
                $isQrLogin = $message_data['isQrLogin'] ?? 0;
                // 二维码登录逻辑，每60秒
                if($isQrLogin){
                    // 生成新的二维码链接
                    $domain=config('app.app_host');
                    $appid=config('app.app_id');
                    $token=urlencode(authcode($client_id,'ENCODE',$appid,100));
                    $qrurl=rtrim($domain,'/') . '/scan/a/' . $token;
                    Gateway::sendToClient($client_id, json_encode(array(
                        'type' => 'codeLoginQr',
                        'qrurl' => $qrurl,
                    )));
                }
                // 如果是扫码登录则不做断开处理
                if(!$user_id && $_SESSION['pong_times'] >= 3 && !$isQrLogin){
                    $_SESSION['pong_times'] = 0;
                    self::closeClient($client_id);
                }
                break;
            case 'ping':
                self::sendStatus($client_id);
                break;
            case 'bindUid':
                self::auth($client_id,$message_data);
                break;
        }
        return;
   }

   protected static function sendStatus($client_id){
        $uid=$_SESSION['user_id'] ?? 0;
        $multiport=false;
        if($uid){
            $arr=Gateway::getClientIdByUid($uid);
            if(count($arr)>1){
                $multiport=true;
            }
        }
        Gateway::sendToClient($client_id, json_encode(array(
            'type' => 'pong',
            'multiport' => $multiport,
        )));
   }

    //验证用户的真实性并绑定
    protected static function auth($client_id, $msg){
        $token=$msg['token'] ?? '';
        $config   = Config::get('jwt');
        $keys     = $config['secret'] ?: [
            'public' => $config['public_key'],
            'private' => $config['private_key'],
            'password' => $config['password'],
        ];
        $provider = new Lcobucci(new Builder(), new Parser(), $config['algo'], $keys);
        try {
            $token=str_replace('bearer ','',$token);
            $jwtData = $provider->decode((string)$token);
        } catch (\Exception $exception) {
            self::closeClient($client_id);
        }

        $userInfo = $jwtData['info']->getValue();
        //解密token中的用户信息
        $userInfo = Aes::decrypt($userInfo, config('app.aes_token_key'));
        //解析json
        $userInfo = (array)json_decode($userInfo, true);
        if(!$userInfo){
            self::closeClient($client_id);
        }
        $_SESSION['user_id']=$userInfo['user_id'];
        $_SESSION['role']=$userInfo['role'];

        if($_SESSION['role'] != 0){
            $user_id = $userInfo['user_id'];
            $is_online = User::isOnline($user_id);
            if ($is_online == 0) {
                //更新客服上线状态
                User::setOnline($user_id, 1);
                Gateway::sendToClient($client_id, json_encode(array(
                    'type'      => 'sign',
                    'data' => ['is_sign' => 1],
                )));
            }
        }

        self::sendStatus($client_id);
    }

    //断开连接
    protected static function closeClient($client_id){
        self::onlineStatistics();
        $_SESSION['user_id']=null;
        Gateway::closeClient($client_id);
    }

    /**
    * 当断开连接时
    * @param int $client_id
    */
    public static function onClose($client_id)
    {
        $user_id=$_SESSION['user_id'] ?? '';
        if($user_id){
            Gateway::sendToAll(json_encode(array(
                'type'      => 'isOnline',
                'time' => time(),
                'data' => ['id'=>$user_id,'is_online'=>0]
            )));

            if($_SESSION['role'] != 0){
                //更新客服离线状态
                User::setOnline($user_id, 0);
            }
        }
        self::onlineStatistics();
    }

    public static function onlineStatistics()
    {
       // 通知后台在线用户数和在线设备数
        $data=[
            'type'      => 'statistics',
            'time' => time(),
            'data' => [
                'onlineCount'=>Gateway::getAllUidCount() ?? 0,
                'clientCount'=>Gateway::getAllClientCount() ?? 0,
            ] 
        ];
        Gateway::sendToGroup('admin-manage', json_encode($data));
        Gateway::sendToUid(1, json_encode($data));
    }
  
}
