package com.ruoyi.system.service.impl;


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.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.google.gson.Gson;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.exception.base.CustomException;
import com.ruoyi.common.utils.PhoneUtils;
import com.ruoyi.common.utils.VerifyCodeUtils;
import com.ruoyi.system.domain.SmsBlacklist;
import com.ruoyi.system.domain.SmsLog;
import com.ruoyi.system.mapper.SmsLogMapper;
import com.ruoyi.system.service.ISmsBlacklistService;
import com.ruoyi.system.service.ISysDictTypeService;
import com.ruoyi.system.service.ShortMessageService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * Created on 19/6/7.
 * 短信API产品的DEMO程序,工程中包含了一个SmsDemo类，直接通过
 * 执行main函数即可体验短信产品API功能(只需要将AK替换成开通了云通信-短信产品功能的AK即可)
 * 工程依赖了2个jar包(存放在工程的libs目录下)
 * 1:aliyun-java-sdk-core.jar
 * 2:aliyun-java-sdk-dysmsapi.jar
 *
 * 备注:Demo工程编码采用UTF-8
 * 国际短信发送请勿参照此DEMO
 */
@Service
public class ShortMessageServiceImpl implements ShortMessageService {

    private Log logger = LogFactory.getLog(ShortMessageServiceImpl.class);

    @Value("${aliyun.sms.accessKeyId}")
    private String accessKeyId ;
    @Value("${aliyun.sms.accessKeySecret}")
    private String accessKeySecret;
    @Value("${aliyun.sms.defaultConnectTimeout}")
    private String defaultConnectTimeout ;
    @Value("${aliyun.sms.defaultReadTimeout}")
    private String defaultReadTimeout;
    @Value("${aliyun.sms.signName}")
    private String signName;
    @Value("${aliyun.sms.duration}")
    private Integer duration;

    @Value("${aliyun.sms.templateCode}")
    private String templateCode;
    @Value("${aliyun.sms.ecardTemplateCode}")
    private String ecardTemplateCode;
//    @Value("${aliyun.sms.template.validateIdentity}")
//    private String templateCodeAccount;

    //产品名称:云通信短信API产品,开发者无需替换
    private static final String product = "Dysmsapi";
    //产品域名,开发者无需替换
    private static final String domain = "dysmsapi.aliyuncs.com";

    @Autowired
    private SmsLogMapper smsLogMapper;
    @Autowired
    public ISysDictTypeService dictTypeService;
    @Autowired
    public ISmsBlacklistService smsBlacklistService;


    @Override
    public AjaxResult sendSmsCommon(String mobile, Integer smsType){
        //校验手机号
        if(!PhoneUtils.isPhoneNumber(mobile)){
            return AjaxResult.error("手机号错误");
        }
        boolean isSuccess = this.sendSms(mobile, smsType);
        if(!isSuccess){
            return AjaxResult.error("发送失败");
        }
        return AjaxResult.success("发送成功");
    }

    /**
     * 发送线上电子卡的用户名密码给用户
     */
    @Override
    public boolean sendSmsECard(String mobileNo, String username, String password,Integer smsType){
//        this.getSmsTemplateAndSign(smsType);
        SmsLog smsLog = new SmsLog();
        smsLog.setType(smsType);
        //验证短信验证码是否频繁
        if(!checkFrequently(mobileNo)){
            logger.error("短信发送频繁 "+mobileNo);
            throw new BaseException("短信发送频繁");
//            throw new BusinessException("短信发送频繁",StatusCodeConstant.rule_error);
        }

        Map<String, String> templateParam = new HashMap<String, String>();
        templateParam.put("username", username);
        templateParam.put("password", password);

        //可自助调整超时时间
        System.setProperty("sun.net.client.defaultConnectTimeout", defaultConnectTimeout);
        System.setProperty("sun.net.client.defaultReadTimeout", defaultReadTimeout);
        SendSmsResponse sendSmsResponse = null;
        try{
            //初始化acsClient,暂不支持region化
            IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
            DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
            IAcsClient acsClient = new DefaultAcsClient(profile);

            //组装请求对象-具体描述见控制台-文档部分内容
            SendSmsRequest request = new SendSmsRequest();
            //必填:待发送手机号
            request.setPhoneNumbers(mobileNo);
            //必填:短信签名-可在短信控制台中找到
            request.setSignName(signName);
            //必填:短信模板-可在短信控制台中找到
            request.setTemplateCode(ecardTemplateCode);
            //可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
            request.setTemplateParam(new Gson().toJson(templateParam));
            //选填-上行短信扩展码(无特殊需求用户请忽略此字段)
            //request.setSmsUpExtendCode("90997");
            //可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
            //request.setOutId("yourOutId");
            //hint 此处可能会抛出异常，注意catch
            sendSmsResponse = acsClient.getAcsResponse(request);
        }catch(Exception e){
            logger.error("ShortMessageServiceImpl sendSms",e);        //throw new BusinessException("短信发送异常",StatusCodeConstant.rule_error);
        }

        smsLog.setCode(ecardTemplateCode);
        smsLog.setPhoneNo(mobileNo);
        smsLog.setMessage(ecardTemplateCode + ":" + new Gson().toJson(templateParam) + "，短信发送返回信息：" + new Gson().toJson(sendSmsResponse));
        Integer status = (int) ((sendSmsResponse != null && sendSmsResponse.getCode().equals("OK")) ? 1 : 0);
        smsLog.setStatus(status);
        smsLog.setUpdateTime(new Date());
        smsLog.setCreateTime(new Date());
        smsLogMapper.insertSmsLog(smsLog);

        if(sendSmsResponse != null && sendSmsResponse.getCode().equals("OK")){
            return true;
        }
        else if(sendSmsResponse != null){
            throw new BaseException(sendSmsResponse.getMessage());
        }
        return false;
    }

    /**
     *
     * @param phoneNumber
     * @return
     */
    @Override
    public boolean sendSms(String phoneNumber,Integer smsType){
        Boolean isSend = dictTypeService.selectDictTypeByType("is_send").getStatus() .equals( "0") ? true:false;//0正常使用
        SmsLog smsLog = new SmsLog();
        smsLog.setType(smsType);
        smsLog.setPhoneNo(phoneNumber);
        smsLog.setUpdateTime(new Date());
        smsLog.setCreateTime(new Date());
        if(isSend){
            String code = VerifyCodeUtils.captchaNumber(4);
            smsLog.setCode(code);
            this.getSmsTemplateAndSign(smsType);
            //验证短信验证码是否频繁
            if(!checkFrequently(phoneNumber)){
                throw new BaseException("短信发送频繁");
            }


            Map<String, String> templateParam = new HashMap<String, String>();
            templateParam.put("code", code);

            //可自助调整超时时间
            System.setProperty("sun.net.client.defaultConnectTimeout", defaultConnectTimeout);
            System.setProperty("sun.net.client.defaultReadTimeout", defaultReadTimeout);
            SendSmsResponse sendSmsResponse = null;
            try{
                //初始化acsClient,暂不支持region化
                IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
                DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
                IAcsClient acsClient = new DefaultAcsClient(profile);

                //组装请求对象-具体描述见控制台-文档部分内容
                SendSmsRequest request = new SendSmsRequest();
                //必填:待发送手机号
                request.setPhoneNumbers(phoneNumber);
                //必填:短信签名-可在短信控制台中找到
                request.setSignName(signName);
                //必填:短信模板-可在短信控制台中找到
                request.setTemplateCode(templateCode);
                //可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
                request.setTemplateParam(new Gson().toJson(templateParam));
                //选填-上行短信扩展码(无特殊需求用户请忽略此字段)
                //request.setSmsUpExtendCode("90997");
                //可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
                //request.setOutId("yourOutId");
                //hint 此处可能会抛出异常，注意catch
                sendSmsResponse = acsClient.getAcsResponse(request);
            }catch(Exception e){
                logger.error("ShortMessageServiceImpl sendSms",e);
                //throw new BusinessException("短信发送异常",StatusCodeConstant.rule_error);
            }

            smsLog.setMessage(templateCode + ":" + new Gson().toJson(templateParam) + "，短信发送返回信息：" + new Gson().toJson(sendSmsResponse));
            Integer status = (int) ((sendSmsResponse != null && sendSmsResponse.getCode().equals("OK")) ? 1 : 0);
            smsLog.setStatus(status);
            smsLogMapper.insertSmsLog(smsLog);
            if(sendSmsResponse != null && sendSmsResponse.getCode().equals("OK")){
                return true;
            }
            else if(sendSmsResponse != null){
                throw new BaseException(sendSmsResponse.getMessage());
            }
        }else{
            smsLog.setCode("123456");
            smsLog.setMessage("模拟发送信息！");
            smsLog.setStatus(1);
            smsLogMapper.insertSmsLog(smsLog);
            return true;
        }

        return false;

    }

    /**
     *
     * @param phoneNumber
     * @param templateParam {"name":"Tom", "code":"123"}
     * @return
     */
    @Override
    public boolean sendSms(String phoneNumber,String templateCode,String templateParam, String code,Integer smsType){

        this.getSmsTemplateAndSign(smsType);
        //验证短信验证码是否频繁
        if(!checkFrequently(phoneNumber)){
            throw new BaseException("短信发送频繁");
        }
        //可自助调整超时时间
        System.setProperty("sun.net.client.defaultConnectTimeout", defaultConnectTimeout);
        System.setProperty("sun.net.client.defaultReadTimeout", defaultReadTimeout);
        SendSmsResponse sendSmsResponse = null;
        try{
            //初始化acsClient,暂不支持region化
            IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
            DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
            IAcsClient acsClient = new DefaultAcsClient(profile);
            //组装请求对象-具体描述见控制台-文档部分内容
            SendSmsRequest request = new SendSmsRequest();
            //必填:待发送手机号
            request.setPhoneNumbers(phoneNumber);
            //必填:短信签名-可在短信控制台中找到
            request.setSignName(signName);
            //必填:短信模板-可在短信控制台中找到
            request.setTemplateCode(templateCode);
            //可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
            request.setTemplateParam(templateParam);
            //选填-上行短信扩展码(无特殊需求用户请忽略此字段)
            //request.setSmsUpExtendCode("90997");
            //可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
            //request.setOutId("yourOutId");
            //hint 此处可能会抛出异常，注意catch
            sendSmsResponse = acsClient.getAcsResponse(request);
        }catch(Exception e){
            logger.error("ShortMessageServiceImpl sendSms",e);
            throw new CustomException("短信发送异常");
        }
        SmsLog smsLog = new SmsLog();
        smsLog.setCreateTime(new Date());
        smsLog.setMessage(templateCode + ":" + templateParam + "，短信发送返回信息：" + new Gson().toJson(sendSmsResponse));
        smsLog.setPhoneNo(phoneNumber);
        smsLog.setStatus((sendSmsResponse != null && sendSmsResponse.getCode().equals("OK")) ? 0 : 1);
        smsLog.setCode(code);
        smsLog.setUpdateTime(new Date());
        smsLog.setCreateTime(new Date());
        smsLogMapper.insertSmsLog(smsLog);

        if(sendSmsResponse != null && sendSmsResponse.getCode().equals("OK")){
            return true;
        }
        else if(sendSmsResponse != null){
            throw new BaseException(sendSmsResponse.getMessage());
        }
        return false;
    }

    /**
     * 验证短信验证码是否有效
     * @param phoneNo
     * @param code
     * @return
     */
    @Override
    public boolean checkCode(String phoneNo, String code) {

        if(StringUtils.isEmpty(phoneNo) || StringUtils.isEmpty(code)){
            throw new BaseException("短信验证缺少手机号码或者验证码");
        }
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.SECOND,- duration);
        SmsLog smsLog = new SmsLog();
        smsLog.setPhoneNo(phoneNo);
//        smsLog.setStatus(0);
        smsLog.setCreateTime(calendar.getTime());
        List<SmsLog> list = smsLogMapper.checkCode(smsLog);
        if(!CollectionUtils.isEmpty(list)){
            //处理验证码已使用
            SmsLog smsLogCheck = list.get(0);
            Boolean isSuccess = code.equals(smsLogCheck.getCode()) ? true : false;
            if(isSuccess){
                //发送成功时将此条code置为已使用,一条记录仅能使用一次
                smsLogCheck.setIsUsed(1);
                smsLogMapper.updateSmsLog(smsLogCheck);
            }
            return isSuccess;
        }else{
            throw new BaseException("验证码已失效，请重新发送！");
        }
    }

    /**
     * 检查短信发送是否频繁 一小时最多5次
     * @param phoneNumber
     * @return
     */
    public boolean checkFrequently(String phoneNumber){
        int count = smsLogMapper.getCountLastHour(phoneNumber);
        if(count >= 5){
            //手机号加入黑名单
            SmsBlacklist insert = new SmsBlacklist();
            insert.setPhoneNo(phoneNumber);
            if(!CollectionUtils.isEmpty(smsBlacklistService.selectSmsBlacklistList(insert))){
                return false;
            }

            smsBlacklistService.insertSmsBlacklist(insert);
            return false;
        }
        return true;
    }

    /**
     * 获取短信模板与签名
     * @param smsType
     */
    private void getSmsTemplateAndSign(Integer smsType){
        if(StringUtils.isEmpty(signName)|| StringUtils.isEmpty(templateCode)){
            String smsTypeDict= dictTypeService.getDictDataByType("sms_type",String.valueOf(smsType));
            if(!StringUtils.isEmpty(smsTypeDict)){
                String[] smsTypeArray = Convert.toStrArray(smsTypeDict);
                signName = smsTypeArray[0];
                templateCode = smsTypeArray[1];
            }
        }
    }

    /**
     * 是否为黑名单
     * @param phonenumber
     * @return
     */
    public Boolean isBlacklist(String phonenumber){
        SmsBlacklist insert = new SmsBlacklist();
        insert.setPhoneNo(phonenumber);
        if(!CollectionUtils.isEmpty(smsBlacklistService.selectSmsBlacklistList(insert))){
            return true;
        }
        return false;
    }
}
