package com.miaxis.app.sms.impl;

import com.miaxis.app.sms.ISmsService;
import com.miaxis.app.sms.domain.SmsParameter;
import com.miaxis.common.constant.SmsTemplateConstants;
import com.miaxis.common.core.domain.Response;
import com.miaxis.common.exception.CustomException;
import com.miaxis.common.sms.Client;
import com.miaxis.common.utils.RedisPrefixUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.net.URLEncoder;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 短信服务层接口实现
 * @Author wwl
 * @Date 2020/12/23
 * @Version 1.0
 */
@Service
public class SmsServiceImpl implements ISmsService {

    private final String MOBILE_REGEX = "^((13[0-9])|(14[0-9])|(15[0-9])|(17[0-9])|(18[0-9])|(19[0-9]))\\d{8}$";//手机号码验证
    private final Integer SMS_MAX_COUNT = 500 ;//每天系统发送最大次数(预留)
    private final Integer MAX_COUNT = 5 ;//每个手机号验证发送最大次数
    private final long SEND_INTERVAL = 3 ;//发送间隔时间


    @Value("${sms_user_name}")
    private String smsUserName;//用户名

    @Value("${sms_password}")
    private String smsPassword;//密码

    @Autowired
    private RedisTemplate redisTemplate;//redis模板引擎

    /**
     * 发送短信验证码
     * @param smsParameter
     * @return
     */
    @Override
    public Response sendVerificationCode(SmsParameter smsParameter) {
        //字符编码
        String charset = "UTF-8";

        //type验证
        List<String> collect = Arrays.stream(SmsTemplateConstants.SMS_TEMPLATE_TYPE)
                .parallel()
                .filter(str -> str.equals(smsParameter.getType()))
                .collect(Collectors.toList());
        if (collect.size()==0){
            throw new CustomException("参数{type}类型错误!");
        }

        //手机号格式验证
        if(smsParameter.getPhone().length() != 11){
            throw new CustomException("手机格式错误!");
        } else {
            Pattern pattern = Pattern.compile(MOBILE_REGEX);
            Matcher matcher = pattern.matcher(smsParameter.getPhone());
            if(!matcher.matches()) {
                throw new CustomException("手机号格式错误!");
            }
        }
        try{

            //生成redis 验证码key前缀 验证次数key前缀
            String smsKeyPrefix = RedisPrefixUtils.getSmsKeyPrefix(smsParameter.getType(), smsParameter.getPhone());
            String smsKeyCountPrefix = RedisPrefixUtils.getSmsKeyCountPrefix(smsParameter.getType(), smsParameter.getPhone());
            smsParameter.setKeyPrefix(smsKeyPrefix);
            smsParameter.setVerificationCount(smsKeyCountPrefix);

            if ("login".equals(smsParameter.getType())){
                smsParameter.setSmsTemplateConstants(SmsTemplateConstants.LOGIN);
            }
            if ("signUp".equals(smsParameter.getType())){
                smsParameter.setSmsTemplateConstants(SmsTemplateConstants.SIGNUP);
            }
            if ("modify".equals(smsParameter.getType())){
                smsParameter.setSmsTemplateConstants(SmsTemplateConstants.MODIFY);
            }

            //验证缓存信息
            Response resultJson = validateMobile(smsParameter);
            if("500".equals(resultJson.getCode().toString())) {
                return resultJson;
            }

            // 生成验证码
            String code="";
            for (int i=0;i<6;i++){
                code += new Random().nextInt(10);
            }
            String content = smsParameter.getSmsTemplateConstants().replace("code",code);

            // 调用发送接口
            Client client = new Client(smsUserName, smsPassword);
            String content1 = URLEncoder.encode(content, charset);
            String ecodeContent = URLEncoder.encode(content1, charset);
            String result = client.mtData(ecodeContent, smsParameter.getPhone(), "", "", "", charset);
            String strCode = result.split("\n")[0];
            long codenum = 0;
            codenum = Long.valueOf(strCode);
            String Info = null;
            if (codenum > 0) {//成功提交
                Info = "发送成功";
                // 写入缓存中
                writeCache(code,smsParameter);
                return Response.success(Info);

            } else if (codenum == 0) {
                Info = "发送失败";
            } else if (codenum == -1) { // 用户名密码不正确
                Info = "用户名密码不正确";
            } else if (codenum == -2) { // 必填选项为空
                Info = "必填选项为空";
            } else if (codenum == -3) { // 短信内容0个字节
                Info = "短信内容0个字节";
            } else if (codenum == -4) { // 0个有效号码
                Info = "0个有效号码";
            } else if (codenum == -5) { // 余额不够
                Info = "余额不够";
            } else if (codenum == -10) { // 用户被禁用
                Info = "用户被禁用";
            } else if (codenum == -11) { // 短信内容过长
                Info = "短信内容过长";
            } else if(codenum == -12){	 //用户无扩展权限
                Info = "无扩展权限";
            } else if(codenum == -13){  //IP地址校验错
                Info = "IP校验错误";
            } else if(codenum == -14){  //内容解析异常
                Info = "内容解析异常";
            } else {
                Info = "未知错误";
            }

            throw new CustomException(Info);
        } catch (Exception e) {
            throw new CustomException(e.getMessage());
        }
    }


    /**
     * 手机号验证
     * keyPrefix : 缓存key前缀
     * verificationCount : 验证次数
     * @param smsParameter
     * @return
     */
    private Response validateMobile(SmsParameter smsParameter){

        if(redisTemplate.hasKey(smsParameter.getVerificationCount())){
            // 验证发送时间
            if (redisTemplate.hasKey(smsParameter.getKeyPrefix())){
                throw new CustomException("验证码还未过期，不能重新发送!",500);
            }

            // 验证发送次数
            Integer count = Integer.valueOf(redisTemplate.opsForValue().get(smsParameter.getVerificationCount()).toString());
            if(count >= MAX_COUNT) {
                throw new CustomException("当前手机号发送验证码次数过多!",500);
            }
        }
        return Response.success();
    }


    /**
     * 写入缓存
     * @param smsParameter
     * @param code
     */
    private void writeCache(String code,SmsParameter smsParameter){

        //该手机号首次获取验证码
        if(!redisTemplate.hasKey(smsParameter.getKeyPrefix()) && !redisTemplate.hasKey(smsParameter.getVerificationCount())){
            synchronized(this){
                //设置该手机号验证码 两分钟过期
                redisTemplate.opsForValue().set(smsParameter.getKeyPrefix() , code, SEND_INTERVAL, TimeUnit.MINUTES);
                //设置该手机号验证次数 一天过期
                redisTemplate.opsForValue().set(smsParameter.getVerificationCount() , "1",1,TimeUnit.DAYS);
            }
        }

        //多次获取验证码
        if (redisTemplate.hasKey(smsParameter.getVerificationCount()) && !redisTemplate.hasKey(smsParameter.getKeyPrefix())){
            //判断该手机验证次数
            Integer count = Integer.valueOf(redisTemplate.opsForValue().get(smsParameter.getVerificationCount()).toString());
            if (count < MAX_COUNT){
                synchronized(this){
                    //该手机号验证次数+1 一天过期
                    redisTemplate.opsForValue().set(smsParameter.getVerificationCount() ,String.valueOf(count+1),1,TimeUnit.DAYS);
                    //设置该手机号验证码 两分钟过期
                    redisTemplate.opsForValue().set(smsParameter.getKeyPrefix() , code, SEND_INTERVAL, TimeUnit.MINUTES);
                }
            }
        }
    }


}
