package ink.wgink.module.sms.manager;

import ink.wgink.exceptions.ParamsException;
import ink.wgink.module.sms.pojo.VerifyCode;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * When you feel like quitting. Think about why you started
 * 当你想要放弃的时候，想想当初你为何开始
 *
 * @ClassName: VerifyCodeManager
 * @Description: 验证码管理
 * @Author: WangGeng
 * @Date: 2020/3/4 5:34 下午
 * @Version: 1.0
 **/
public class VerifyCodeManager {

    private static final Logger LOG = LoggerFactory.getLogger(VerifyCodeManager.class);
    private static final VerifyCodeManager verifyCodeManager = VerifyCodeManagerBuilder.verifyCodeManager;
    private Map<String, VerifyCode> verifyCodeMap = new ConcurrentHashMap<>();
    /**
     * 有效时间60s
     */
    public static final long EXPIRE_TIME = 120000L;

    private VerifyCodeManager() {
    }

    public static VerifyCodeManager getInstance() {
        return verifyCodeManager;
    }

    /**
     * 设置验证码
     *
     * @param key
     * @param code
     */
    public void setVerificationCode(String key, String code) {
        VerifyCode verifyCode = new VerifyCode();
        verifyCode.setCode(code);
        verifyCode.setTime(System.currentTimeMillis());
        verifyCodeMap.put(key, verifyCode);
    }

    /**
     * 获取验证码
     *
     * @param key
     * @return
     */
    public String getVerifyCode(String key) {
        VerifyCode verifyCode = verifyCodeMap.get(key);
        if (verifyCode != null && (System.currentTimeMillis() - verifyCode.getTime() < EXPIRE_TIME)) {
            return verifyCode.getCode();
        }
        return null;
    }

    /**
     * 是否有有效的验证码
     *
     * @param key
     * @return
     */
    public long effectiveVerificationCodeTimeRemaining(String key) {
        VerifyCode verifyCode = verifyCodeMap.get(key);
        if (verifyCode == null) {
            return 0;
        }
        long timeRemaining = System.currentTimeMillis() - verifyCode.getTime();
        if (timeRemaining >= EXPIRE_TIME) {
            return 0;
        }
        return EXPIRE_TIME - timeRemaining;
    }

    /**
     * 清理使用后的验证码
     *
     * @param key
     */
    public void clearUsedVerifyCode(String key) {
        verifyCodeMap.remove(key);
    }

    /**
     * 校验验证码
     *
     * @param key
     * @param code
     */
    public void checkVerifyCode(String key, String code) {
        String verificationCode = getVerifyCode(key);
        if (StringUtils.isBlank(verificationCode)) {
            throw new ParamsException("验证码无效");
        }
        if (!StringUtils.equals(code, verificationCode)) {
            throw new ParamsException("验证码不匹配");
        }
        clearUsedVerifyCode(key);
    }

    /**
     * 删除过期验证码
     */
    public void clearExpireTimeCode() {
        int size = 0;
        long currentTime = System.currentTimeMillis();
        for (Map.Entry<String, VerifyCode> kv : verifyCodeMap.entrySet()) {
            VerifyCode verifyCode = kv.getValue();
            if (currentTime - verifyCode.getTime() > EXPIRE_TIME) {
                verifyCodeMap.remove(kv.getKey());
                size++;
            }
        }
        LOG.trace("本次清除超时验证码:{}个", size);
    }

    private static class VerifyCodeManagerBuilder {
        public static VerifyCodeManager verifyCodeManager = new VerifyCodeManager();
    }

}
