package com.cm.common.token.app;

import com.alibaba.fastjson.JSONObject;
import com.cm.common.constants.ISystemConstant;
import com.cm.common.enums.AppTokenTypeEnum;
import com.cm.common.exception.TokenException;
import com.cm.common.token.app.entity.AppToken;
import com.cm.common.token.app.entity.AppTokenUser;
import com.cm.common.utils.AesUtil;
import com.cm.common.utils.DateUtil;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * When you feel like quitting. Think about why you started
 * 当你想要放弃的时候，想想当初你为何开始
 *
 * @ClassName: AppTokenManager
 * @Description: AppToken管理
 * @Author: WangGeng
 * @Date: 2019-08-02 11:08
 * @Version: 1.0
 **/
public class AppTokenManager {

    private static final Logger LOG = LoggerFactory.getLogger(AppTokenManager.class);
    private static AppTokenManager appTokenManager = AppTokenManagerBuilder.appTokenManager;
    private static final Map<String, AppToken> tokens = new ConcurrentHashMap();

    private AppTokenManager() {
    }

    public static AppTokenManager getInstance() {
        return appTokenManager;
    }

    /**
     * 获取token
     *
     * @param token
     * @return
     */
    public AppToken getToken(String token) {
        AppToken appToken = tokens.get(token);
        if (appToken != null) {
            appToken.setLastTime(System.currentTimeMillis());
        }
        return appToken;
    }

    /**
     * 添加token
     *
     * @param token
     * @param type
     * @param appTokenUser
     */
    public synchronized void addToken(String token, AppTokenTypeEnum appTokenTypeEnum, AppTokenUser appTokenUser) {
        AppToken appToken = new AppToken();
        appToken.setToken(token);
        appToken.setAppTokenTypeEnum(appTokenTypeEnum);
        appToken.setLastTime(System.currentTimeMillis());
        appToken.setAppTokenUser(appTokenUser);
        appToken.setUserId(appTokenUser.getId());
        for (Map.Entry<String, AppToken> kvs : tokens.entrySet()) {
            if (StringUtils.equals(appTokenUser.getId(), kvs.getValue().getUserId())) {
                tokens.remove(kvs.getValue().getToken());
                break;
            }
        }
        tokens.put(token, appToken);
    }

    public AppTokenUser parseToAppTokenUser(String token) throws TokenException {
        String userInfo = null;
        try {
            userInfo = AesUtil.aesCommonDecoder(ISystemConstant.APP_TOKEN_AES_KEY, new String(Base64.decodeBase64(token), "UTF-8"));
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            throw new TokenException("Token解码异常");
        }
        JSONObject userInfoObj = JSONObject.parseObject(userInfo);
        if (userInfoObj == null) {
            throw new TokenException("Token非法");
        }
        String appTokenSign = userInfoObj.getString(ISystemConstant.APP_TOKEN_SIGN);
        if (StringUtils.isBlank(appTokenSign)) {
            LOG.debug("Token标识为空");
            throw new TokenException("Token非法");
        }
        if (!StringUtils.startsWith(appTokenSign, ISystemConstant.APP_TOKEN_VERIFY)) {
            LOG.debug("Token标识开头错误");
            throw new TokenException("Token非法");
        }
        String[] appTokenSignArray = appTokenSign.split("_");
        if (appTokenSignArray.length != 3) {
            LOG.debug("Token标识格式长度异常，应为3，这里为：{}", appTokenSignArray.length);
            throw new TokenException("Token非法");
        }
        try {
            new Date(Long.parseLong(appTokenSignArray[2]));
        } catch (NumberFormatException e) {
            e.printStackTrace();
            LOG.debug("Token时间戳异常");
            throw new TokenException("Token非法");
        }
        return JSONObject.toJavaObject(userInfoObj, AppTokenUser.class);
    }

    /**
     * 当前用户列表
     *
     * @return
     */
    public List<AppTokenUser> listCurrentUsers() {
        List<AppTokenUser> users = new ArrayList<>();
        for (Map.Entry<String, AppToken> kvs : tokens.entrySet()) {
            AppToken appToken = kvs.getValue();
            users.add(appToken.getAppTokenUser());
        }
        return users;
    }

    /**
     * 清空超时Token
     */
    public synchronized void clearTimeoutToken() {
        long currentTime = System.currentTimeMillis();
        List<String> clearTokenKeys = new ArrayList<>(0);
        for (Map.Entry<String, AppToken> kvs : tokens.entrySet()) {
            AppToken appToken = kvs.getValue();
            // 超过10分钟
            if (currentTime - appToken.getLastTime() > 600000L) {
                clearTokenKeys.add(kvs.getKey());
            }
        }
        for (String tokenKey : clearTokenKeys) {
            tokens.remove(tokenKey);
        }
        LOG.debug("本次共清理超时Token:{}个", clearTokenKeys.size());
    }

    private static class AppTokenManagerBuilder {
        public static final AppTokenManager appTokenManager = new AppTokenManager();
    }

}
