package com.malk.utils;

import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.TimedCache;
import org.apache.commons.lang3.StringUtils;

/**
 * token 过期处理
 *
 * <p>提供两类 API：</p>
 * <ol>
 *   <li><b>单参 key</b>（{@link #put(String, String, Long)} / {@link #get(String)}）— 兼容原有调用方，
 *       key 自包含命名空间（如 {@code "dingtalk:appKey123"}）</li>
 *   <li><b>namespace + key</b>（{@link #put(String, String, String, Long)} / {@link #get(String, String)}）—
 *       推荐多租户 / 多应用场景使用，namespace 与 key 拼接为 {@code "{namespace}:{key}"} 后存入底层缓存。
 *       namespace 为 null 或空时退化为单参 key 模式。</li>
 * </ol>
 *
 * <p>典型用法（多租户）：</p>
 * <pre>
 * // mjava-pro 多租户场景
 * UtilToken.put(tenantId, "dingtalk:" + appKey, token, 7200_000L);
 * String t = UtilToken.get(tenantId, "dingtalk:" + appKey);
 *
 * // 基座单租户场景
 * UtilToken.put("dingtalk:appKey", token, 7200_000L);
 * String t = UtilToken.get("dingtalk:appKey");
 * </pre>
 */
public abstract class UtilToken {

    private static final TimedCache<String, String> TIMED_CACHE = CacheUtil.newTimedCache(0);

    /**
     * 命名空间分隔符
     */
    public static final String NS_SEPARATOR = ":";

    /// ---------- 单参 key API（向后兼容） ----------

    public static void put(String key, String value, Long timeout) {
        if (timeout > 5000) timeout -= 5000; // 避免极端情况, 冗余5s容错处理
        /** 设置消逝时间 */
        TIMED_CACHE.put(key, value, timeout);
    }

    public static String get(String key) {
        // 不刷新消逝时间
        return TIMED_CACHE.get(key, false);
    }

    public static String getWithRefresh(String key) {
        // 重新刷新消逝时间
        return TIMED_CACHE.get(key);
    }

    /// ---------- namespace + key API（推荐多租户场景使用） ----------

    /**
     * 按 namespace 隔离写入；namespace 为空时退化为单参 key 模式
     *
     * @param namespace 命名空间（如 tenantId / vendor / corp 标识）；null 或空字符串退化
     * @param key       业务 key（如 {@code "dingtalk:" + appKey}）
     * @param value     token / ticket 等待缓存的字符串值
     * @param timeout   TTL 毫秒；put 内部会冗余扣 5s
     */
    public static void put(String namespace, String key, String value, Long timeout) {
        put(buildKey(namespace, key), value, timeout);
    }

    /**
     * 按 namespace 隔离读取；不刷新消逝时间
     */
    public static String get(String namespace, String key) {
        return get(buildKey(namespace, key));
    }

    /**
     * 按 namespace 隔离读取并刷新消逝时间
     */
    public static String getWithRefresh(String namespace, String key) {
        return getWithRefresh(buildKey(namespace, key));
    }

    /**
     * 拼接 namespace + key 为底层缓存 key；namespace 空白时直接返回 key
     */
    public static String buildKey(String namespace, String key) {
        return StringUtils.isBlank(namespace) ? key : namespace + NS_SEPARATOR + key;
    }
}
