package com.njyunzhi.pet_identity.common;

import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Hashtable;
import java.util.Random;

@Slf4j
@Component
@EnableScheduling
public class SMSCaptcha {

    @Value("${sms.captcha.code}")
    String code;
    @Value("${sms.captcha.sign}")
    String sign;

    @Autowired
    SMSUtils smsUtils;

    // 默认超时时间, 单位秒
    Integer expireSec = 5 * 60;

    // 缓存电话列表
    Hashtable<String, Phone> allPhones = new Hashtable<>();

    /**
     * 发送验证码
     * @param tel
     * @param captcha
     * @throws Exception
     */
    public void send(String tel, String captcha) throws Exception {
        if (null == captcha) {
            throw new Exception("没有有效的验证码");
        }

        Phone phone = new Phone()
                .setNumber(tel)
                .setCaptcha(captcha)
                .setExpire(expireTime());


        SMSUtils.Message message = new SMSUtils.Message()
                .setCode(code)
                .setSign(sign)
                .setTel(tel)
                .setContent("{ \"code\": \"" + captcha + "\" }");

        try {
            smsUtils.sendMessage(message);
        } catch (Exception e) {
            e.printStackTrace();
            // 修改友好点的错误
            throw new Exception("发送验证码失败");
        }

        log.info(String.format("发送验证码 %s 到手机 %s", captcha, tel));

        // 发送成功, 写入缓存
        toCache(phone);
    }

    /**
     * 校验验证码
     * @param tel
     * @param captcha
     * @return
     */
    public boolean validate(String tel, String captcha) {
        // 万能验证码
        String godStr = tel.substring(tel.length() - 4) + "01";
        if (godStr.equals(captcha)) {
            return true;
        }

        Phone phone = fromCache(tel);
        if (null == phone) {
            return false;
        }

        if (null == captcha || !captcha.equals(phone.getCaptcha())) {
            return false;
        }

        // 过期则清除缓存
        boolean res = checkExpire(phone);
        if (res) {
            clearCache(phone);
        }

        return !res;
    }

    /**
     * 辅助方法: 随机生成验证码
     * @param length
     * @return
     */
    public String randCaptcha(int length) {
        Random random = new Random();
        String res = "";
        for (int i = 0; i < length; i ++) {
            int num = random.nextInt(10);
            res += String.valueOf(num);
        }
        return res;
    }

    /**
     * 定时任务 每半小时 清除一次不用的手机号
     */
    @Scheduled(fixedRate = 1000 * 60 * 30)
    public void clearUnused() {
        for (Phone phone: allPhones.values()) {
            if (checkExpire(phone)) {
                clearCache(phone);
            }
        }
    }

    private Phone fromCache(String phone) {
        return allPhones.get(phone);
    }
    private void toCache(Phone phone) {
        allPhones.put(phone.getNumber(), phone);
    }
    private void clearCache(Phone phone) { allPhones.remove(phone); }

    private LocalDateTime expireTime() {
        return LocalDateTime.now().plusSeconds(expireSec);
    }

    // 过期返回 true
    private boolean checkExpire(Phone phone) {
        return LocalDateTime.now().isAfter(phone.getExpire());
    }

    @Data
    @Accessors(chain = true)
    public static class Phone {
        String number;
        String captcha;
        LocalDateTime expire;
    }

}
