package com.fufan.mtsaas.aliyun;

import com.alibaba.fastjson.JSON;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
import com.fufan.mtsaas.aliyun.enums.VerificationCodeResultEnum;
import com.fufan.mtsaas.aliyun.model.SendVerificationCode;
import com.fufan.mtsaas.aliyun.model.Sms;
import com.fufan.mtsaas.aliyun.model.VerifyVerificationCode;
import com.fufan.mtsaas.constant.RedisKeyConstant;
import com.fufan.mtsaas.util.CodeUtil;
import com.google.common.collect.ImmutableMap;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class SmsService {

    /**
     * 短信发送成功
     */
    private static final String SUCCESS = "OK";

    private static final String CODE_KEY_NAME = "code";

    @Autowired
    private ApplicationProperties applicationProperties;

    @Autowired
    private SmsProperties smsProperties;
//    @Autowired
    private VerificationCodeGenerator verificationCodeGenerator;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Value("${send.sms.button}")
    private  boolean button;
    /**
     * 发送短信
     *
     * @param sms 短信
     */
    public String send(Sms sms) {
        // 不真实发送
//        if (!applicationProperties.getSms().isRealSend()) {
//            return;
//        }
        try {
            DefaultProfile profile = DefaultProfile.getProfile(smsProperties.getRegionId(),
                    smsProperties.getAccessKeyId(), smsProperties.getAccessKeySecret());
            IAcsClient client = new DefaultAcsClient(profile);
            SendSmsRequest request = new SendSmsRequest();
            request.setSignName(StringUtils.defaultIfBlank(sms.getSignName(), smsProperties.getDefaultSignName()));
            request.setTemplateCode(sms.getTemplateCode());
            request.setPhoneNumbers(sms.getPhoneNumbers());
            request.setTemplateParam(JSON.toJSONString(sms.getTemplateParam()));
            request.setSmsUpExtendCode(sms.getSmsUpExtendCode());
            request.setOutId(sms.getOutId());
            log.info("发送短信请求：{}", JSON.toJSONString(request));
            SendSmsResponse response = client.getAcsResponse(request);
            log.info("发送短信响应：{}", JSON.toJSONString(response));
            // 失败
            if (!SUCCESS.equalsIgnoreCase(response.getCode())) {
                return "发送短信失败: " + response.getMessage();
            }
        } catch (ClientException e) {
            log.error(e.getMessage(), e);
            return "发送短信失败: " + e.getMessage();
//            throw new com.hosjoy.common.exception.ClientException("发送短信失败: " + e.getMessage());
        }
        return "";
    }

    /**
     * 发送短信验证码
     */
    public String sendVerificationCode(SendVerificationCode sendVerificationCode) {


        // 生成验证码
        //String code = this.generateVerificationCode(sendVerificationCode.getPhoneNumbers());
        String code = CodeUtil.generate();

        String templateCode = StringUtils.defaultIfBlank(sendVerificationCode.getTemplateCode(),
                smsProperties.getVerificationCodeTemplateCode());

        if(button){
            stringRedisTemplate.opsForValue()
                    .set(getVerificationCodeRedisKey(templateCode,
                            sendVerificationCode.getPhoneNumber()), "666666", 5, TimeUnit.MINUTES);
            return "ok";
        }
        // 调用阿里云短信
        String result = this.send(
                Sms.builder()
                        .signName(sendVerificationCode.getSignName())
                        .templateCode(templateCode)
                        .phoneNumbers(sendVerificationCode.getPhoneNumber())
                        .templateParam(ImmutableMap.of(CODE_KEY_NAME, code))
                        .build()
        );
        log.info("手机号为" + sendVerificationCode.getPhoneNumber() + "生成验证码为:" + code + "结果为" + result);
        // 存入Redis, 5分钟过时
        stringRedisTemplate.opsForValue()
                .set(getVerificationCodeRedisKey(templateCode,
                        sendVerificationCode.getPhoneNumber()), code, 5, TimeUnit.MINUTES);
        if(StringUtils.isNotEmpty(result)){
            return "";
        }else {
            return result;
        }
    }

    /**
     * 验证短信验证码
     */
    public VerificationCodeResultEnum verifyVerificationCode(VerifyVerificationCode verifyVerificationCode) {
        String templateCode = StringUtils.isNotBlank(verifyVerificationCode.getTemplateCode())
                ? verifyVerificationCode.getTemplateCode()
                : smsProperties.getVerificationCodeTemplateCode();

        String redisKey = getVerificationCodeRedisKey(
                templateCode, verifyVerificationCode.getPhoneNumber());
        String inRedisCode = stringRedisTemplate.opsForValue().get(redisKey);
        //检查手机是否被锁
        String lock = stringRedisTemplate.opsForValue().get("LOCK-" + verifyVerificationCode.getPhoneNumber());
        if(StringUtils.isNotEmpty(lock)){
            //该手机被锁住，请稍后再试
            return VerificationCodeResultEnum.MAX_TRY;
        }
        // 验证码不存在
        if (StringUtils.isBlank(inRedisCode)) {
            return checkLock(verifyVerificationCode.getPhoneNumber());

//            return VerificationCodeResultEnum.NOT_EXIST;
        } else {
            // 验证码正确
            if (verifyVerificationCode.getCode().equals(inRedisCode)) {
                stringRedisTemplate.delete(redisKey);
                stringRedisTemplate.delete("TRY-" + verifyVerificationCode.getPhoneNumber());
                stringRedisTemplate.delete("LOCK-" + verifyVerificationCode.getPhoneNumber());
                return VerificationCodeResultEnum.CORRECT;
            }

            return checkLock(verifyVerificationCode.getPhoneNumber());

            // 验证码错误
//            return VerificationCodeResultEnum.ERROR;
        }
    }

    /**
     * 检查试错次数 - Liby 20220707
     * @param phoneNumber
     * @return
     */
    private VerificationCodeResultEnum checkLock(String phoneNumber){
    //检查手机输出次数
        String tryNo = stringRedisTemplate.opsForValue().get("TRY-" + phoneNumber);


        if(StringUtils.isEmpty(tryNo)){
            tryNo = "0";
        }else {
            tryNo = String.valueOf(Integer.valueOf(tryNo).intValue() + 1);
        }

        stringRedisTemplate.opsForValue().set("TRY-" + phoneNumber,
                tryNo);

        if(StringUtils.isNotEmpty(tryNo) && Integer.valueOf(tryNo) >= 5){
            //连续试错5次，自动上锁30分钟
            stringRedisTemplate.opsForValue().set("LOCK-" + phoneNumber, "1", 30, TimeUnit.MINUTES);
            //该手机被锁住，请稍后再试
            return VerificationCodeResultEnum.MAX_TRY;
        }

        // 验证码错误
        return VerificationCodeResultEnum.ERROR;
    }

    /**
     * 获取验证码Redis key
     */
    private String getVerificationCodeRedisKey(String templateCode, String phoneNumbers) {
        return RedisKeyConstant.SMS_VERIFICATION_CODE_PREFIX + templateCode + ":" + phoneNumbers;
//        return "";

    }


    /**
     * 生成验证码
     */
    private String generateVerificationCode(String phoneNumber) {
        return verificationCodeGenerator.generate(phoneNumber);
    }

}
