package com.ruoyi.sms.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.code.PublicCommon;
import com.ruoyi.common.cos.TxApiSdkUtils;
import com.ruoyi.common.exception.enums.CoreExceptionEnum;
import com.ruoyi.enums.sms.SmsEnums;
import com.ruoyi.enums.user.UserEnums;
import com.ruoyi.frequency.customer.entity.Customer;
import com.ruoyi.frequency.customer.mapper.CustomerMapper;
import com.ruoyi.frequency.sale.entity.Sale;
import com.ruoyi.frequency.sale.mapper.SaleMapper;
import com.ruoyi.frequency.store.entity.Store;
import com.ruoyi.frequency.store.mapper.StoreMapper;
import com.ruoyi.response.ResponseData;
import com.ruoyi.sms.MessageCodeService;
import com.ruoyi.sms.controller.vo.SendMesReq;
import com.ruoyi.sms.utils.AliSmsUtil;
import com.ruoyi.sms.utils.FuseCloudSmsUtil;
import com.ruoyi.utils.BusinessUtil;
import com.ruoyi.vo.UserVo;
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 org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import java.util.Random;


/**
 * @author twx
 * @Description
 * @Date
 **/
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class AppMessageCodeServiceImpl implements MessageCodeService {

    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private CustomerMapper customerMapper;


    @Value("${app.name}")
    private String appName;

    @Autowired
    private FuseCloudSmsUtil fuseCloudSmsUtil;

    @Autowired
    private AliSmsUtil aliSmsUtil;

    @Autowired
    private BusinessUtil businessUtil;

    @Override
    public ResponseData sendMsg(SendMesReq req, UserVo userVo, String smsType) {


        // 获取注册短信时,先校验图形验证码
        String _code = redisTemplate.opsForValue().get(req.getKey());
        if (StrUtil.isBlankOrUndefined(_code)) {
            return ResponseData.error(CoreExceptionEnum.FIGURE_CODE_NOT_EXIST);
        }
        if (!StrUtil.equalsIgnoreCase(_code, req.getCaptcha())) {
            return ResponseData.error(CoreExceptionEnum.FIGURE_CODE_ERROR);
        }

        //判断用户信息
        ResponseData responseData = judgeUser(req, userVo.getUserId());
        if (!responseData.getSuccess()){
            return responseData;
        }

        //发送短信
        return this.getCode(req.getAreaCode(),req.getMobile(),req.getType(),req.getUserType(),smsType);
    }



    private ResponseData judgeUser(SendMesReq req,Long userId){

        /**
         * 1 用户注册 2 用户登录 3 修改密码  4 忘记密码 5 小程序登录绑定手机号 6 微信登录绑定手机号 7 苹果登录绑定手机号 8 支付密码校验
         * 9 换绑手机号-验证原有手机号 10 换绑手机号-验证新手机号
         */
        Integer type = req.getType();

        switch (SmsEnums.getSmsEnums(type)) {
            case REGISTER:
                ResponseData responseData = judgeAccount(req.getUserType(), req.getAccount());
                if (!responseData.getSuccess()){
                    return responseData;
                }

                return judgeRegisterMobile(req.getUserType(), req.getAreaCode(),req.getMobile(),null);
            case LOGIN:
                if (ObjectUtil.isNotEmpty(req.getLoginType())) {
                    return judgeMobile(req.getUserType(), req.getAreaCode(),req.getMobile(),null,req.getLoginType());
                }else {
                    return judgeMobile(req.getUserType(), req.getAreaCode(),req.getMobile(),null);
                }

            case CHANGE_PWD:
                return judgeMobile(req.getUserType(), req.getAreaCode(),req.getMobile(),userId);
            case FORGET_PWD:
                return judgeMobile(req.getUserType(), req.getAreaCode(),req.getMobile(),null);
            case PAY_PWD:
                return judgeMobile(req.getUserType(), req.getAreaCode(),req.getMobile(),userId);
            case OLD_MOBILE_BIND:
                return judgeMobile(req.getUserType(), req.getAreaCode(),req.getMobile(),userId);
            case NEW_MOBILE_BIND:
                return judgeRegisterMobile(req.getUserType(), req.getAreaCode(),req.getMobile(),userId);
        }
        return ResponseData.success();
    }

    @Autowired
    private StoreMapper storeMapper;

    @Autowired
    private SaleMapper saleMapper;

    /**
     * 判断账号是否存在
     * @param userType
     * @param account
     * @return
     */
    private ResponseData judgeAccount(Integer userType,String account){

        if (ObjectUtil.isEmpty(account)){
            return ResponseData.success();
        }

        switch (UserEnums.getUserEnums(userType)){
            case customer:
                Customer customer = customerMapper.selectOne(new QueryWrapper<Customer>().lambda()
                        .eq(Customer::getAccount, account)
                        .ne(Customer::getDelFlag, PublicCommon.删除));
                if (customer != null) {
                    return ResponseData.error(CoreExceptionEnum.ACCOUNT_HAS_EXIST);
                }
                break;
            case store:
                Store store = storeMapper.selectOne(new QueryWrapper<Store>().lambda()
                        .eq(Store::getAccount, account)
                        .ne(Store::getDelFlag, PublicCommon.删除));
                if (store != null) {
                    return ResponseData.error(CoreExceptionEnum.ACCOUNT_HAS_EXIST);
                }
                break;
            case sale:
                Sale sale = saleMapper.selectOne(new QueryWrapper<Sale>().lambda()
                        .eq(Sale::getMobile, account)
                        .ne(Sale::getDelFlag, PublicCommon.删除));
                if (sale != null) {
                    return ResponseData.error(CoreExceptionEnum.ACCOUNT_HAS_EXIST);
                }
                break;
            default:
                break;
        }

        return ResponseData.success();
    }


    /**
     * 判断手机号是否存在
     * @param userType
     * @param areaCode
     * @param mobile
     * @param userId
     * @return
     */
    private ResponseData judgeMobile(Integer userType,String areaCode,String mobile,Long userId){


        if (ObjectUtil.isEmpty(mobile)){
            return ResponseData.success();
        }

        switch (UserEnums.getUserEnums(userType)){
            case customer:
                Customer customer = (Customer) businessUtil.getUserObject(UserEnums.customer, areaCode, mobile);
                if (customer == null) {
                    return ResponseData.error(CoreExceptionEnum.ACCOUNT_NOT_EXIST);
                } else if (userId != null && !customer.getId().equals(userId)) {
                    return ResponseData.error(CoreExceptionEnum.MOBILE_BIND_MAKE);
                } else if (customer.getDelFlag().equals(PublicCommon.禁用)) {
                    return ResponseData.error(CoreExceptionEnum.ACCOUNT_DISABLE);
                }

                break;
            case store:
                Store store = (Store) businessUtil.getUserObject(UserEnums.store, areaCode, mobile);
                if (store == null) {
                    return ResponseData.error(CoreExceptionEnum.ACCOUNT_NOT_EXIST);
                } else if (userId != null && !store.getId().equals(userId)) {
                    return ResponseData.error(CoreExceptionEnum.MOBILE_BIND_MAKE);
                } else if (store.getDelFlag().equals(PublicCommon.禁用)) {
                    return ResponseData.error(CoreExceptionEnum.ACCOUNT_DISABLE);
                }

                break;
            case sale:
                Sale sale = (Sale) businessUtil.getUserObject(UserEnums.sale, areaCode, mobile);
                if (sale == null) {
                    return ResponseData.error(CoreExceptionEnum.ACCOUNT_NOT_EXIST);
                } else if (userId != null && !sale.getId().equals(userId)) {
                    return ResponseData.error(CoreExceptionEnum.MOBILE_BIND_MAKE);
                } else if (sale.getDelFlag().equals(PublicCommon.禁用)) {
                    return ResponseData.error(CoreExceptionEnum.ACCOUNT_DISABLE);
                }

                break;
            default:
                break;
        }

        return ResponseData.success();
    }

    /**
     * 判断手机号是否存在
     * @param userType
     * @param areaCode
     * @param mobile
     * @param userId
     * @return
     */
    private ResponseData judgeMobile(Integer userType,String areaCode,String mobile,Long userId,Integer loginType){


        if (ObjectUtil.isEmpty(mobile)){
            return ResponseData.success();
        }

        switch (UserEnums.getUserEnums(userType)){
            case customer:
                Customer customer = (Customer) businessUtil.getUserObject(UserEnums.customer, areaCode, mobile);

                if (customer == null) {
                    break;
                }
                if (userId != null && !customer.getId().equals(userId)) {
                    return ResponseData.error(CoreExceptionEnum.MOBILE_BIND_MAKE);
                } else if (customer.getDelFlag().equals(PublicCommon.禁用)) {
                    return ResponseData.error(CoreExceptionEnum.ACCOUNT_DISABLE);
                }

                break;
            case store:
                Store store = (Store) businessUtil.getUserObject(UserEnums.store, areaCode, mobile);
                if (store == null) {
                    break;
                }
                if (userId != null && !store.getId().equals(userId)) {
                    return ResponseData.error(CoreExceptionEnum.MOBILE_BIND_MAKE);
                } else if (store.getDelFlag().equals(PublicCommon.禁用)) {
                    return ResponseData.error(CoreExceptionEnum.ACCOUNT_DISABLE);
                }

                break;
            case sale:
                Sale sale = (Sale) businessUtil.getUserObject(UserEnums.sale, areaCode, mobile);

                if (sale == null) {
                    break;
                }

                if (userId != null && !sale.getId().equals(userId)) {
                    return ResponseData.error(CoreExceptionEnum.MOBILE_BIND_MAKE);
                } else if (sale.getDelFlag().equals(PublicCommon.禁用)) {
                    return ResponseData.error(CoreExceptionEnum.ACCOUNT_DISABLE);
                }

                break;
            default:
                break;
        }

        return ResponseData.success();
    }

    /**
     * 判断手机号是否存在
     * @param userType
     * @param areaCode
     * @param mobile
     * @param userId
     * @return
     */
    private ResponseData judgeRegisterMobile(Integer userType,String areaCode,String mobile,Long userId){


        if (ObjectUtil.isEmpty(mobile)){
            return ResponseData.success();
        }

        switch (UserEnums.getUserEnums(userType)){
            case customer:
                Customer customer = (Customer) businessUtil.getUserObject(UserEnums.customer, areaCode, mobile);
                if (customer == null) {
                    return ResponseData.success();
                } else if (userId != null && !customer.getId().equals(userId)) {
                    return ResponseData.error(CoreExceptionEnum.MOBILE_BIND_MAKE);
                } else if (customer != null ){
                    if (userId == null || !userId.equals(customer.getId())){
                        return ResponseData.error(CoreExceptionEnum.PHONE_HAS_EXIST);
                    }
                }else if (customer.getDelFlag().equals(PublicCommon.禁用)) {
                    return ResponseData.error(CoreExceptionEnum.ACCOUNT_DISABLE);
                }

                break;
            case store:
                Store store = (Store) businessUtil.getUserObject(UserEnums.store, areaCode, mobile);
                if (store == null) {
                    return ResponseData.success();
                } else if (userId != null && !store.getId().equals(userId)) {
                    return ResponseData.error(CoreExceptionEnum.MOBILE_BIND_MAKE);
                } else if (store != null){
                    return ResponseData.error(CoreExceptionEnum.PHONE_HAS_EXIST);
                }else if (store.getDelFlag().equals(PublicCommon.禁用)) {
                    return ResponseData.error(CoreExceptionEnum.ACCOUNT_DISABLE);
                }

                break;
            case sale:
                Sale sale = (Sale) businessUtil.getUserObject(UserEnums.sale, areaCode, mobile);
                if (sale == null) {
                    return ResponseData.success();
                } else if (userId != null && !sale.getId().equals(userId)) {
                    return ResponseData.error(CoreExceptionEnum.MOBILE_BIND_MAKE);
                }  else if (sale != null){
                    return ResponseData.error(CoreExceptionEnum.PHONE_HAS_EXIST);
                }else if (sale.getDelFlag().equals(PublicCommon.禁用)) {
                    return ResponseData.error(CoreExceptionEnum.ACCOUNT_DISABLE);
                }

                break;
            default:
                break;
        }

        return ResponseData.success();
    }

    /**
     * 发送短信方法
     * @param areaCode 手机区号
     * @param mobile  手机号
     * @param type   发送短信类型
     * @param userType  用户类型
     * @param smsType  三方短信类型
     * @return
     * @throws Exception
     */
    public ResponseData getCode(String areaCode,String mobile, Integer type,Integer userType,String smsType) {
        //生成随机验证码
        String code = randomNumStr(6);
        redisTemplate.opsForValue().set(code + type + areaCode + mobile + userType, System.currentTimeMillis() + "," + type + "," + code + "," + mobile, 15 * 60);

        //根据不同三方短信
        switch (smsType){
            case "1":
                String codeResult = "";
                //助通短信
                try {
                    codeResult = fuseCloudSmsUtil.sendSms(areaCode + mobile, "【" + appName + "】您的验证码是" + code + " 如非本人操作，请忽略本短信!");
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                Map map = JSONObject.parseObject(codeResult, Map.class);
                //判断短信是否发送成功
                if (StringUtils.isEmpty(codeResult) || !"success".equals(map.get("msg"))) {
                    return ResponseData.error(map.get("msg").toString());
                }
                break;
            case "2":
                //阿里短信
                Boolean isSendSuccess = aliSmsUtil.sendMessage(areaCode + mobile, code);
                //判断短信是否发送成功
                if (!isSendSuccess) {
                    return ResponseData.error(CoreExceptionEnum.SMS_SEND_FAIL);
                }
                break;
            case "3":
                //腾讯云短信
                JSONObject jsonObject = TxApiSdkUtils.sendSmsMsg(mobile,code);
                //判断短信是否发送成功
                if (ObjectUtil.isEmpty(jsonObject)) {
                    return ResponseData.error(CoreExceptionEnum.SMS_SEND_FAIL);
                }

                String str = Objects.requireNonNull(jsonObject).getString("SendStatusSet");
                JSONArray jsonArray = JSONArray.parseArray(str);
                String sendStatusSet = jsonArray.get(0).toString();
                JSONObject jsonObject1 = JSONObject.parseObject(sendStatusSet);
                String resCode = jsonObject1.getString("Code");
                String message = jsonObject1.getString("Message");

                if(!"Ok".equals(resCode)){
                    System.err.println(message);
                    return ResponseData.error(CoreExceptionEnum.SMS_SEND_FAIL);
                }
                break;
            default:
                return ResponseData.success(code);
        }
        return ResponseData.success();
    }


    /**
     * 功能描述：产生随机字符串
     *
     * @param length 长度
     * @return 产生对应长度的字符串
     * @author wangyf 2017-12-22 11:13
     */
    public static final String randomNumStr(int length) {
        if (length < 1) {
            return null;
        }
        char[] randBuffer = new char[length];
        for (int i = 0; i < randBuffer.length; i++) {
            randBuffer[i] = numbers[numGen.nextInt(9)];
        }
        return new String(randBuffer);
    }

    private static Random numGen = new Random();

    private static char[] numbers = ("0123456789").toCharArray();

}
