package com.yanzuoguang.token;

import com.yanzuoguang.util.base.ObjectHelper;
import com.yanzuoguang.util.cache.MemoryCache;
import com.yanzuoguang.util.exception.CodeException;
import com.yanzuoguang.util.helper.JsonHelper;
import com.yanzuoguang.util.helper.StringHelper;
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 MemoryCache<TokenData> cache = new MemoryCache<>();


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

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

    /**
     * 获取当前的登录信息
     *
     * @param checkFlag 是否抛出异常
     * @param cls       需要获取的数据的类型
     * @param <T>       数据类型
     * @return 缓存的数据
     */
    public static <T extends Object> T get(boolean checkFlag, Class<T> cls) {
        String id = getCurrentId();
        TokenData tokenData = cache.get(id);
        if (tokenData == null) {
            if (checkFlag) {
                throw new CodeException("请先登录");
            }
            return null;
        }
        boolean isEmpty = tokenData.getData() == null || tokenData.getData().isEmpty();
        boolean isExpire = tokenData.getExpire() < System.currentTimeMillis();
        boolean isToken = !StringHelper.isEmpty(tokenData.getToken()) && (isEmpty || isExpire);
        if (isToken) {
            tokenData = tokenLoad.load(tokenData.getToken());
            if (tokenData != null) {
                cache.put(id, tokenData);
            }
        }
        if (tokenData == null || tokenData.getData() == null) {
            if (checkFlag) {
                throw new CodeException("请先登录");
            }
            return null;
        }

        if (ObjectHelper.isSub(cls, tokenData.getData().getClass())) {
            return (T) tokenData.getData();
        } else {
            String json = JsonHelper.serialize(tokenData.getData());
            return JsonHelper.deserialize(json, cls);
        }
    }

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

    /**
     * 获取字段值
     *
     * @param checkFlag 是否抛出异常
     * @param cls       字段值类型
     * @param field     字段值
     * @param <T>       类型
     * @return 对象
     */
    public static <T extends Object> 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, 0, data);
    }

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


    /**
     * 缓存数据
     *
     * @param token   标记
     * @param expire  有效期
     * @param dataPwd 数据密码
     * @param data    数据时间
     */
    public static void write(String token, String dataPwd, long expire, Object data) {
        String id = getCurrentId();
        TokenData tokenData = cache.get(id);
        if (tokenData == null) {
            tokenData = new TokenData();
            cache.put(id, tokenData);
        }
        tokenData.setToken(token);
        tokenData.setDataPwd(dataPwd);
        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) {
        String id = getCurrentId();
        TokenData tokenData = JsonHelper.deserialize(tokenString, TokenData.class);
        cache.put(id, tokenData);
        tokenData.setWrite(false);
        return tokenData;
    }

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

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