<?php
// +----------------------------------------------------------------------
// | 麦沃德科技赋能开发者，助力中小企业发展 
// +----------------------------------------------------------------------
// | Copyright (c) 2017～2024  www.wdadmin.cn    All rights reserved.
// +----------------------------------------------------------------------
// | Wdadmin系统产品软件并不是自由软件，不加密，并不代表开源，未经许可不可自由转售和商用
// +----------------------------------------------------------------------
// | Author: MY WORLD Team <bd@maiwd.cn>   www.wdadmin.cn
// +----------------------------------------------------------------------
namespace core\util;

use core\exception\AuthException;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use think\facade\Cache;

/**
 * Desc : token工具类
 * Create on 2025/12/12 上午11:23
 * Create by woailuo
 */
class TokenAuth
{
    /**
     *创建token
     * @param int $id 编码  一般传入用户id
     * * @param string $type 类型（admin，api）
     * * @param array $params 参数  传入id, name
     * * @param int $expire_time 有效期
     * @return array
     */
    public static function createToken(int $id, string $type, array $params = [], int $expire_time = 0): array
    {
        $domain = app()->request->host();
        $time = time();
        $key = env('app.jwt_key', 'WdUniPHP$%^');
        $default_expire = config('project.token.expire_time', 2592000);
        $payload = [
            'iss' => $domain,
            'aud' => $domain,
            'iat' => $time,
            'nbf' => $time,
            'exp' => $expire_time ? $time + $expire_time : $time + $default_expire,
        ];
        $payload = array_merge($payload, $params);
        $payload['jti'] = $id . "_" . $type;

        $token = JWT::encode($payload, $key, 'HS256');
        $cache_token = Cache::store("jwt")->get("token_" . $payload['jti']) ?: Cache::get("token_" . $payload['jti']);

        $cache_token_arr = $cache_token ?: [];
        
        // 防止重复添加相同的token
        if (!in_array($token, $cache_token_arr)) {
            $cache_token_arr[] = $token;
            Cache::store("jwt")->tag("token")->set("token_" . $payload['jti'], $cache_token_arr);
        }

        $params = $payload ;
        return compact('token', 'params');
    }

    /**
     * Desc 解析token
     * Create on 2025/12/12 下午2:06
     * Create by woailuo
     */
    public static function parseToken(string $token , string $type): array
    {
        $key = env('app.jwt_key', 'WdUniPHP$%^');
        try {
            $decoded = JWT::decode($token, new Key($key, 'HS256'));
        } catch (\Exception) {
            throw new AuthException('Token无效', 401);
        }

        if (!empty($decoded)) {
            $decoded_array = (array)$decoded;
            $jti_parts = explode('_', $decoded_array['jti']);
            if (count($jti_parts) != 2 || $jti_parts[1] != $type) {
                throw new AuthException('Token类型不匹配', 401);
            }
            $cache_token = Cache::store("jwt")->get("token_" . $decoded_array['jti']) ?: Cache::get("token_" . $decoded_array['jti']);
            if (empty($cache_token) || !in_array($token, $cache_token)) {
                throw new AuthException('Token已失效，请重新登录', 401);
            }
            return $decoded_array;
        } else {
            throw new AuthException('Token解析失败', 401);
        }
    }

    /**
     * Desc 清理 token
     * Create on 2025/12/12 下午2:30
     * Create by woailuo
     */
    public static function clearToken(int $id , string $type, string $token) {
        $jti = $id . "_" . $type;
        if (!empty($token)) {
            $cache_token = Cache::store("jwt")->get("token_" . $jti) ?: Cache::get("token_" . $jti);
            if (!empty($cache_token)) {
                $updated_tokens = array_filter($cache_token, function ($t) use ($token) {
                    return $t !== $token;
                });
                Cache::store("jwt")->tag("token")->set("token_" . $jti, array_values($updated_tokens));
            } else {
                Cache::store("jwt")->tag("token")->set("token_" . $jti, []);
            }
        } else {
            Cache::store("jwt")->tag("token")->set("token_" . $jti, []);
        }
    }

}