package com.diagbot.service.impl;

import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.diagbot.entity.SwsVerInfo;
import com.diagbot.exception.CommonErrorCode;
import com.diagbot.exception.CommonException;
import com.diagbot.exception.ServiceErrorCode;
import com.diagbot.service.SmsVerService;
import com.diagbot.util.DateUtil;
import com.diagbot.util.GsonUtil;
import com.diagbot.util.SmsCodeUtil;
import com.diagbot.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;

/**
 * @Description:
 * 短信验证接口实现
 * 阿里短信验证码发送
 * @author: gaodm
 * @time: 2018/9/4 16:25
 */
@Service
@Slf4j
public class SmsVerServiceImpl implements SmsVerService {
    @Autowired
    @Qualifier("redisTemplateForSms")
    private RedisTemplate redisForSms;

    @Autowired
    private IAcsClient acsClient;

    private byte[] serializeKey(Object o) {
        return redisForSms.getKeySerializer().serialize(o);
    }

    private byte[] serializeValue(Object o) {
        return redisForSms.getValueSerializer().serialize(o);
    }

    private Object deserializeValue(byte[] b) {
        return redisForSms.getValueSerializer().deserialize(b);
    }

    private byte[] getUserSmsKey(String mobile) {
        String userSmsFormat = "user_sms_%s";
        return serializeKey(String.format(userSmsFormat, mobile));
    }

    public String smsSend(String mobile,String smsTemplateCode){
        if (StringUtil.isBlank(mobile)){
            throw new CommonException(CommonErrorCode.PARAM_IS_NULL,
                    "电话号码不能为空!");
        }

        //组装请求对象-具体描述见控制台-文档部分内容
        SendSmsRequest request = new SendSmsRequest();
        //必填:待发送手机号
        request.setPhoneNumbers(mobile);
        //必填:短信签名-可在短信控制台中找到
        request.setSignName("杭州朗通");
        //必填:短信模板-可在短信控制台中找到
        request.setTemplateCode(smsTemplateCode);
        String code = SmsCodeUtil.getVerCode();
        String json="{\"code\":\""
                + code
                + "\"}";
        //可选:模板中的变量替换JSON串,如模板内容为"您的验证码是${code}，有效期为3分钟，感谢您使用朗通医疗云平台。"时,此处的值为
        request.setTemplateParam(json);

        //选填-上行短信扩展码(无特殊需求用户请忽略此字段)
        //request.setSmsUpExtendCode("90997");
        //可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
        //request.setOutId("yourOutId");
        try {
            //此处可能会抛出异常，注意catch
            SendSmsResponse rsp = acsClient.getAcsResponse(request);
            System.out.println(GsonUtil.toJson(rsp));
            if ((null == rsp) || !(rsp.getCode().equals("OK"))){
                throw new CommonException(ServiceErrorCode.SMS_SEND_ERROR);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new CommonException(ServiceErrorCode.SMS_SEND_ERROR);
        }
        return code;
    }

    /**
     * 创建用户短信验证信息
     */
    @Override
    public Boolean createSmsVerification(SwsVerInfo swsVerInfo){
        if (null == swsVerInfo){
            throw new CommonException(CommonErrorCode.PARAM_IS_NULL,
                    "用户短信验证信息不能为空!");
        }
        if (StringUtil.isBlank(swsVerInfo.getMobile())){
            throw new CommonException(CommonErrorCode.PARAM_IS_NULL,
                    "用户电话不能为空!");
        }
        if (StringUtil.isBlank(swsVerInfo.getCode())){
            throw new CommonException(CommonErrorCode.PARAM_IS_NULL,
                    "验证码不能为空!");
        }
        swsVerInfo.setCreateTime(DateUtil.now());
        final Date expireDate = DateUtil.addMinutes(DateUtil.now(), 3);
        swsVerInfo.setExpireTime(expireDate);
        final byte[] redis_key = getUserSmsKey(swsVerInfo.getMobile());
        redisForSms.execute(new RedisCallback<Object>() {
            @Override
            public Object doInRedis(RedisConnection connection) throws DataAccessException {
                //获取旧的
                byte[] bytes = connection.get(redis_key);
                //删除旧的
                if (bytes != null) {
                    connection.del(bytes);
                }
                //设置新的
                connection.setEx(
                        redis_key,
                        (expireDate.getTime() - DateUtil.now().getTime()) / 1000,
                        serializeValue(swsVerInfo)
                );
                return true;
            }
        });
        return true;
    }

    /**
     * 验证短信验证码是否有效
     */
    @Override
    public Boolean verifySmsVerification(SwsVerInfo swsVerInfo){
        if (null == swsVerInfo){
            throw new CommonException(CommonErrorCode.PARAM_IS_NULL,
                    "用户短信验证信息不能为空!");
        }
        if (StringUtil.isBlank(swsVerInfo.getMobile())){
            throw new CommonException(CommonErrorCode.PARAM_IS_NULL,
                    "用户电话不能为空!");
        }
        if (StringUtil.isBlank(swsVerInfo.getCode())){
            throw new CommonException(CommonErrorCode.PARAM_IS_NULL,
                    "短信验证码不能为空!");
        }
        //从redis中取出
        final byte[] redis_key = getUserSmsKey(swsVerInfo.getMobile());
        SwsVerInfo swsVerInfoRes = (SwsVerInfo) redisForSms.execute(new RedisCallback<SwsVerInfo>() {
            @Override
            public SwsVerInfo doInRedis(RedisConnection connection) throws DataAccessException {
                byte[] bytes = connection.get(redis_key);
                if (bytes == null) {
                    return null;
                }
                return (SwsVerInfo) deserializeValue(bytes);
            }
        });
        if (swsVerInfoRes == null) {
            log.info("用户短信验证信息不存在!用户电话：{}", swsVerInfo.getMobile());
            throw new CommonException(CommonErrorCode.NOT_EXISTS,
                    "用户短信验证信息不存在!");
        }
        //判断是否是想要的对象
        if (!swsVerInfoRes.getMobile().equals(swsVerInfo.getMobile())) {
            log.info("用户电话不一致! 用户电话：{}", swsVerInfo.getMobile());
            throw new CommonException(CommonErrorCode.PARAM_IS_ERROR,
                    "用户电话不一致!");
        }
        if (!swsVerInfoRes.getCode().equals(swsVerInfo.getCode())) {
            log.info("短信验证码输入有误!用户电话：{}，验证码：{}", swsVerInfo.getMobile(),swsVerInfo.getCode());
            throw new CommonException(CommonErrorCode.PARAM_IS_ERROR,
                    "短信验证码输入有误!");
        }
        //判断是否过期
        if (!DateUtil.after(swsVerInfoRes.getExpireTime(), DateUtil.now())) {
            log.info("短息验证码已过期，请重新获取!用户电话：{}，过期时间：{}", swsVerInfo.getMobile(), swsVerInfoRes.getExpireTime());
            throw new CommonException(CommonErrorCode.PARAM_IS_ERROR,
                    "短息验证码已过期，请重新获取!");
        }
        return true;
    }

    /**
     * 获取用户短信验证码信息
     * @param mobile 用户电话
     * @return 用户短信验证码信息
     */
    @Override
    public SwsVerInfo getSmsVerification(String mobile){
        return (SwsVerInfo) redisForSms.execute(new RedisCallback<Object>() {
            @Override
            public Object doInRedis(RedisConnection connection) throws DataAccessException {
                byte[] redis_key = getUserSmsKey(mobile);
                byte[] bytes = connection.get(redis_key);
                if (bytes == null) {
                    return null;
                }
                return deserializeValue(bytes);
            }
        });
    }

    /**
     * 删除用户短信验证码信息
     */
    @Override
    public Boolean deleteSmsVerification(String mobile){
        final byte[] redis_key = getUserSmsKey(mobile);
        Long l = (Long) redisForSms.execute(new RedisCallback<Long>() {
            @Override
            public Long doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.del(redis_key);
            }
        });
        return l > 0;
    }
}
