package com.yanzuoguang.token;

import com.yanzuoguang.util.YzgError;
import com.yanzuoguang.util.base.ObjectHelper;
import com.yanzuoguang.util.helper.JsonHelper;
import com.yanzuoguang.util.helper.RsaHelper;
import com.yanzuoguang.util.helper.StringHelper;
import com.yanzuoguang.util.log.Log;
import com.yanzuoguang.util.vo.MapRow;

/**
 * 登录请求
 *
 * @author 颜佐光
 */
public class TokenHelper {

    /**
     * 动态加载token支持对象
     */
    private static TokenLoad tokenLoad = null;

    /**
     * 获取动态加载支持对象
     *
     * @return 动态加载支持对象
     */
    public static TokenLoad getTokenLoad() {
        return tokenLoad;
    }

    /**
     * 设置动态加载支持对象
     *
     * @param tokenLoad 设置值
     */
    public static void setTokenLoad(TokenLoad tokenLoad) {
        TokenHelper.tokenLoad = tokenLoad;
    }

    /**
     * 内存缓存
     */
    protected final static ThreadLocal<TokenData> cache = new ThreadLocal<>();


    /**
     * 获取当前线程编号
     *
     * @return 线程编号
     */
    private static String getCurrentId() {
        return String.valueOf(Thread.currentThread().getId());
    }

    /**
     * 获取当前的登录信息
     *
     * @return 缓存的数据
     */
    public static TokenData getTokenData(boolean readNewToken) {
        TokenData cacheTokenData = cache.get();
        if (cacheTokenData == null) {
            return null;
        }
        // 获取最新的token
        if (!readNewToken) {
            return cacheTokenData;
        }

        boolean isEmpty = cacheTokenData.getData() == null || cacheTokenData.getData().isEmpty();
        boolean isExpire = cacheTokenData.getExpire() < System.currentTimeMillis();
        boolean isToken = !StringHelper.isEmpty(cacheTokenData.getToken()) && (isEmpty || isExpire);
        if (isToken) {
            TokenData databaseToken = tokenLoad.load(cacheTokenData.getToken());
            if (databaseToken == null || databaseToken.getData() == null) {
                return null;
            } else {
                cache.set(databaseToken);
                return databaseToken;
            }
        }
        return cacheTokenData;
    }

    /**
     * 获取当前的登录信息
     *
     * @param cls 需要获取的数据的类型
     * @param <T> 数据类型
     * @return 缓存的数据
     */
    public static <T> T get(Class<T> cls) {
        return get(true, cls);
    }

    /**
     * 获取当前的登录信息
     *
     * @param checkFlag 是否抛出异常
     * @param cls       需要获取的数据的类型
     * @param <T>       数据类型
     * @return 缓存的数据
     */
    public static <T> T get(boolean checkFlag, Class<T> cls) {
        return get(checkFlag, cls, true);
    }

    /**
     * 获取当前的登录信息
     *
     * @param checkFlag 是否抛出异常
     * @param cls       需要获取的数据的类型
     * @param <T>       数据类型
     * @return 缓存的数据
     */
    public static <T> T get(boolean checkFlag, Class<T> cls, boolean readNewToken) {
//        Log.info(TokenHelper.class, "获取登陆信息结果");
        TokenData tokenData = getTokenData(readNewToken);
        if (tokenData == null) {
            if (checkFlag) {
                throw YzgError.getRuntimeException("061");
            }
            return null;
        }
        if (ObjectHelper.isSub(cls, tokenData.getData().getClass())) {
            return (T) tokenData.getData();
        } else {
            String json = JsonHelper.serialize(tokenData.getData());
            T result = JsonHelper.deserialize(json, cls);
            return result;
        }
    }

    /**
     * 获取字段值
     *
     * @param cls   字段值类型
     * @param field 字段值
     * @param <T>   类型
     * @return 对象
     */
    public static <T> T getField(Class<T> cls, String field) {
        return getField(true, cls, field);
    }

    /**
     * 获取字段值
     *
     * @param checkFlag 是否抛出异常
     * @param cls       字段值类型
     * @param field     字段值
     * @param <T>       类型
     * @return 对象
     */
    public static <T> T getField(boolean checkFlag, Class<T> cls, String field) {
        MapRow row = get(checkFlag, MapRow.class);
        Object value = null;
        if (row.containsKey(field)) {
            value = row.get(field);
        }
        return StringHelper.to(cls, value);
    }

    /**
     * 缓存数据
     *
     * @param token 标记
     * @param data  数据时间
     */
    public static void write(String token, Object data) {
        write(token, StringHelper.EMPTY, null, 0, data);
    }

    /**
     * 缓存数据
     *
     * @param token 标记
     * @param data  数据时间
     */
    public static void write(String token, RsaHelper.RsaInfo rsaInfo, Object data) {
        write(token, StringHelper.EMPTY, rsaInfo, 0, data);
    }

    /**
     * 缓存数据
     *
     * @param token  标记
     * @param expire 有效期
     * @param data   数据时间
     */
    public static void write(String token, long expire, Object data) {
        write(token, StringHelper.EMPTY, null, expire, data);
    }

    /**
     * 缓存数据
     *
     * @param token   标记
     * @param expire  有效期
     * @param dataPwd 数据密码
     * @param data    数据时间
     */
    public static void write(String token, String dataPwd, long expire, Object data) {
        write(token, dataPwd, null, expire, data);
    }


    /**
     * 缓存数据
     *
     * @param token   标记
     * @param rsaInfo RSA信息,包含公钥和私钥
     * @param expire  有效期
     * @param dataPwd 数据密码
     * @param data    数据时间
     */
    public static void write(String token, String dataPwd, RsaHelper.RsaInfo rsaInfo, long expire, Object data) {
        TokenData tokenData = cache.get();
        if (tokenData == null) {
            tokenData = new TokenData();
            cache.set(tokenData);
        }
        tokenData.setToken(token);
        tokenData.setDataPwd(dataPwd);
        if (rsaInfo != null) {
            tokenData.setPublicKey(rsaInfo.getPublicKey());
            tokenData.setPrivateKey(rsaInfo.getPrivateKey());
        }
        if (expire > 0) {
            tokenData.setExpire(expire);
        }
        if (tokenData.getData() == null) {
            tokenData.setData(new MapRow());
        }
        ObjectHelper.writeWithFrom(tokenData.getData(), data);
        tokenData.setWrite(true);
    }

    /**
     * 设置登录标记字符串(用于初始化设置,本次修改不会写入到数据库)
     *
     * @param tokenString 登录标记字符串
     */
    public static TokenData setTokenString(String tokenString) {
        TokenData tokenData = JsonHelper.deserialize(tokenString, TokenData.class);
        if (tokenData != null) {
            tokenData.setWrite(false);
        }
        cache.set(tokenData);
        return tokenData;
    }

    /**
     * 获取登录标记字符串,自动要删除数据
     *
     * @return 登录标记字符粗
     */
    public static String getTokenString() {
        TokenData tokenData = cache.get();
        if (tokenData == null) {
            return StringHelper.EMPTY;
        }
        return JsonHelper.serialize(tokenData);
    }


    /**
     * 删除缓存信息
     */
    public static void remove() {
        cache.remove();
    }
}