package com.njcn.user.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.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njcn.common.pojo.constant.PatternRegex;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.common.pojo.response.HttpResult;
import com.njcn.common.utils.PubUtils;
import com.njcn.common.utils.sm.Sm4Utils;
import com.njcn.redis.pojo.enums.RedisKeyEnum;
import com.njcn.redis.utils.RedisUtil;
import com.njcn.user.enums.AppRoleEnum;
import com.njcn.user.enums.MessageEnum;
import com.njcn.user.enums.UserResponseEnum;
import com.njcn.user.mapper.AppUserMapper;
import com.njcn.user.pojo.constant.UserState;
import com.njcn.user.pojo.constant.UserType;
import com.njcn.user.pojo.po.Role;
import com.njcn.user.pojo.po.User;
import com.njcn.user.pojo.po.UserSet;
import com.njcn.user.pojo.po.app.AppInfoSet;
import com.njcn.user.pojo.po.app.AppSendMsg;
import com.njcn.user.service.*;
import com.njcn.web.utils.RestTemplateUtil;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.Objects;
import java.util.Random;

/**
 * 类的介绍：
 *
 * @author xuyang
 * @version 1.0.0
 * @createTime 2023/6/7 14:42
 */
@Service
@AllArgsConstructor
public class AppUserServiceImpl extends ServiceImpl<AppUserMapper, User> implements IAppUserService {

    private static final Logger logger = LoggerFactory.getLogger(AppUserServiceImpl.class);

    private final RedisUtil redisUtil;

    private final IAppSendMsgService appSendMsgService;

    private final IAppInfoSetService appInfoSetService;

    private final IUserSetService userSetService;

    private final IRoleService roleService;

    private final IUserRoleService userRoleService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void setMessage(String phone, String devCode, String type) {
        if (!PubUtils.match(PatternRegex.PHONE_REGEX, phone)){
            throw new BusinessException(UserResponseEnum.REGISTER_PHONE_WRONG);
        }
        try {
            String msgTemplate;
            switch (type) {
                case "0":
                    msgTemplate = MessageEnum.getTemplateByCode(0);
                    break;
                case "1":
                    msgTemplate = MessageEnum.getTemplateByCode(1);
                    break;
                case "2":
                    msgTemplate = MessageEnum.getTemplateByCode(2);
                    break;
                case "3":
                    msgTemplate = MessageEnum.getTemplateByCode(3);
                    break;
                case "4":
                    msgTemplate = MessageEnum.getTemplateByCode(4);
                    break;
                case "5":
                    msgTemplate = MessageEnum.getTemplateByCode(5);
                    break;
                default:
                    throw new BusinessException(UserResponseEnum.CODE_TYPE_ERROR);
            }
            //type为4，账号替换为新手机号
            if (!msgTemplate.equalsIgnoreCase(MessageEnum.REGISTER.getTemplateCode())) {
                User user = this.lambdaQuery().eq(User::getPhone,phone).one();
                if ("4".equalsIgnoreCase(type)) {
                    //注册，无需判断手机号与设备的匹配
                    if (user != null) {
                        throw new BusinessException(UserResponseEnum.REGISTER_PHONE_FAIL);
                    }
                } else {
                    if (null == user) {
                        throw new BusinessException(UserResponseEnum.LOGIN_USERNAME_NOT_FOUND);
                    } else {
                        user.setDevCode(devCode);
                        logger.info("更新手机id：" + devCode);
                        this.updateById(user);
                    }
                }
            }
            //开始执行短信发送
            //设置超时时间-可自行调整
            System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
            System.setProperty("sun.net.client.defaultReadTimeout", "10000");
            //初始化ascClient需要的几个参数
            //短信API产品名称（短信产品名固定，无需修改）
            final String product = "Dysmsapi";
            //短信API产品域名（接口地址固定，无需修改）
            final String domain = "dysmsapi.aliyuncs.com";
            //替换成你的AK
            //你的accessKeyId,参考本文档步骤2
            final String accessKeyId = "LTAI4FxsR76x2dq3w9c5puUe";
            //你的accessKeySecret，参考本文档步骤2
            final String accessKeySecret = "GxkTR8fsrvHtixTlD9UPmOGli35tZs";
            //初始化ascClient,暂时不支持多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.setMethod(MethodType.POST);
            request.setPhoneNumbers(phone);
            //必填:短信签名-可在短信控制台中找到
            request.setSignName("灿能云");
            //必填:短信模板-可在短信控制台中找到，发送国际/港澳台消息时，请使用国际/港澳台短信模版
            request.setTemplateCode(msgTemplate);
            String vcode = getMessageCode();
            String code = "{\"code\":\"" + vcode + "\"}";
            request.setTemplateParam(code);
            //请求失败这里会抛ClientException异常
            SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
            String key = RedisKeyEnum.SMS_LOGIN_KEY.getKey() + phone;
            if (sendSmsResponse.getCode() != null && "OK".equals(sendSmsResponse.getCode())) {
                //成功发送短信验证码后，保存进redis
                redisUtil.saveByKey(key, vcode);
            } else {
                throw new BusinessException(UserResponseEnum.SEND_CODE_FAIL);
            }
            redisUtil.saveByKey(key, vcode);
            AppSendMsg appSendMsg = new AppSendMsg();
            appSendMsg.setPhone(phone);
            appSendMsg.setMessage(vcode);
            appSendMsg.setSendTime(LocalDateTime.now());
            appSendMsg.setSendStatus(sendSmsResponse.getCode() == null ? "无状态" : sendSmsResponse.getCode());
            appSendMsgService.save(appSendMsg);
        } catch (Exception e) {
            logger.error("发送短信异常，异常为："+e.getMessage());
            if (e.getMessage().length() < 10) {
                throw new BusinessException(UserResponseEnum.getCodeByMsg(e.getMessage()));
            } else {
                throw new BusinessException(UserResponseEnum.SEND_CODE_FAIL);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void register(String phone, String code, String devCode) {
        if (!PubUtils.match(PatternRegex.PHONE_REGEX, phone)){
            throw new BusinessException(UserResponseEnum.REGISTER_PHONE_WRONG);
        }
        if (StringUtils.isBlank(devCode)) {
            throw new BusinessException(UserResponseEnum.DEV_CODE_WRONG);
        }
        judgeCode(phone, code);
        //先根据手机号查询是否已被注册
        User user = this.lambdaQuery().eq(User::getPhone,phone).one();
        if (!Objects.isNull(user)){
            throw new BusinessException(UserResponseEnum.REGISTER_PHONE_REPEAT);
        } else {
            //新增用户配置表
            UserSet userSet = userSetService.addAppUserSet();
            //新增用户表
            User newUser = cloneUserBoToUser(phone,devCode,userSet);
            //新增用户角色关系表
            Role role = roleService.getRoleByCode(AppRoleEnum.TOURIST.getCode());
            userRoleService.addUserRole(newUser.getId(), Collections.singletonList(role.getId()));
            //消息默认配置
            AppInfoSet appInfoSet = new AppInfoSet();
            appInfoSet.setUserIndex(newUser.getId());
            appInfoSet.setDeviceInfo(1);
            appInfoSet.setEventInfo(1);
            appInfoSet.setSystemInfo(1);
            appInfoSet.setHarmonicInfo(1);
            appInfoSetService.save(appInfoSet);
            //发送用户初始密码
            sendPasswordMessage(phone,newUser.getId());
        }
    }

    @Override
    public Object autoLogin(String phone, String devCode) {
        //获取登录信息
        Object object = autoLogin(phone);
        if (Objects.isNull(object)){
            throw new BusinessException(UserResponseEnum.LOGIN_ERROR);
        }
        return object;
    }

    @Override
    public void modifyPsd(String userId, String phone, String code, String password, String devCode) {
        if (!PubUtils.match(PatternRegex.PHONE_REGEX, phone)){
            throw new BusinessException(UserResponseEnum.REGISTER_PHONE_WRONG);
        }
        if (StringUtils.isBlank(devCode)) {
            throw new BusinessException(UserResponseEnum.DEV_CODE_WRONG);
        }
        judgeCode(phone, code);
        //判断用户是否存在
        User user = this.lambdaQuery().eq(User::getId,userId).one();
        if (Objects.isNull(user)){
            throw new BusinessException(UserResponseEnum.LOGIN_USERNAME_NOT_FOUND);
        }
        String secretPassword = userSetService.updatePassword(userId, password);
        user.setPassword(secretPassword);
        user.setPwdValidity(LocalDateTime.now());
        user.setLoginTime(LocalDateTime.now());
        user.setDevCode(devCode);
        this.updateById(user);
    }

    @Override
    public void resetPsd(String phone, String code, String password, String devCode) {
        if (!PubUtils.match(PatternRegex.PHONE_REGEX, phone)){
            throw new BusinessException(UserResponseEnum.REGISTER_PHONE_WRONG);
        }
        if (StringUtils.isBlank(devCode)) {
            throw new BusinessException(UserResponseEnum.DEV_CODE_WRONG);
        }
        judgeCode(phone, code);
        //判断用户是否存在
        User user = this.lambdaQuery().eq(User::getPhone,phone).one();
        if (Objects.isNull(user)){
            throw new BusinessException(UserResponseEnum.LOGIN_USERNAME_NOT_FOUND);
        }
        String secretPassword = userSetService.updatePassword(user.getId(), password);
        user.setPassword(secretPassword);
        user.setPwdValidity(LocalDateTime.now());
        user.setLoginTime(LocalDateTime.now());
        user.setDevCode(devCode);
        this.updateById(user);
    }

    @Override
    public void confirmCode(String phone, String code, String devCode) {
        if (!PubUtils.match(PatternRegex.PHONE_REGEX, phone)){
            throw new BusinessException(UserResponseEnum.REGISTER_PHONE_WRONG);
        }
        if (StringUtils.isBlank(devCode)) {
            throw new BusinessException(UserResponseEnum.DEV_CODE_WRONG);
        }
        judgeCode(phone, code);
    }

    @Override
    public void rebindPhone(String userId, String phoneNew, String code, String devCode) {
        if (!PubUtils.match(PatternRegex.PHONE_REGEX, phoneNew)){
            throw new BusinessException(UserResponseEnum.REGISTER_PHONE_WRONG);
        }
        if (StringUtils.isBlank(devCode)) {
            throw new BusinessException(UserResponseEnum.DEV_CODE_WRONG);
        }
        judgeCode(phoneNew, code);
        User user = this.lambdaQuery().eq(User::getPhone,phoneNew).one();
        if (!Objects.isNull(user)){
            throw new BusinessException(UserResponseEnum.REGISTER_PHONE_REPEAT);
        }
        user = new User();
        User user2 = this.lambdaQuery().eq(User::getId,userId).one();
        user2.setName(phoneNew);
        user2.setLoginName(phoneNew);
        user2.setPhone(phoneNew);
        user2.setDevCode(devCode);
        this.updateById(user2);
    }


    /**
     * 自定义获取验证码，固定为字母和数字的组合
     */
    private String getMessageCode() {
        String result = "";
        char[] numbers = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
        //填充数字
        for (int i = 0; i < 6; i++) {
            int numberIndex = new Random().nextInt(10);
            result = result + numbers[numberIndex];
        }
        return result;
    }

    private void judgeCode(String phone, String code) {
        String key = RedisKeyEnum.SMS_LOGIN_KEY.getKey() + phone;
        String redisCode = redisUtil.getStringByKey(key);
        if (StringUtils.isEmpty(redisCode) || !code.equalsIgnoreCase(redisCode)) {
            throw new BusinessException(UserResponseEnum.LOGIN_WRONG_CODE);
        } else {
            //存在且正确的验证，用完即删
            redisUtil.delete(key);
        }
    }

    /**
     * 发送默认密码短信给用户
     * @param phone
     * @param userId
     */
    public void sendPasswordMessage(String phone, String userId) {
            String msgTemplate = MessageEnum.getTemplateByCode(3);
            //开始执行短信发送
            //设置超时时间-可自行调整
            System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
            System.setProperty("sun.net.client.defaultReadTimeout", "10000");
            //初始化ascClient需要的几个参数
            //短信API产品名称（短信产品名固定，无需修改）
            final String product = "Dysmsapi";
            //短信API产品域名（接口地址固定，无需修改）
            final String domain = "dysmsapi.aliyuncs.com";
            //替换成你的AK
            //你的accessKeyId,参考本文档步骤2
            final String accessKeyId = "LTAI4FxsR76x2dq3w9c5puUe";
            //你的accessKeySecret，参考本文档步骤2
            final String accessKeySecret = "GxkTR8fsrvHtixTlD9UPmOGli35tZs";
            //初始化ascClient,暂时不支持多region（请勿修改）
            IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
        try {
            DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
            IAcsClient acsClient = new DefaultAcsClient(profile);
            SendSmsRequest request = new SendSmsRequest();
            request.setMethod(MethodType.POST);
            request.setPhoneNumbers(phone);
            //必填:短信签名-可在短信控制台中找到
            request.setSignName("灿能云");
            //必填:短信模板-可在短信控制台中找到，发送国际/港澳台消息时，请使用国际/港澳台短信模版
            request.setTemplateCode(msgTemplate);
            String password = redisUtil.getStringByKey(userId);
            String code = "{\"pwd\":\"" + password + "\"}";
            request.setTemplateParam(code);
            //请求失败这里会抛ClientException异常
            SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
            if (sendSmsResponse.getCode() != null && "OK".equals(sendSmsResponse.getCode())) {
                //成功发送短信验证码后，删除用户密码信息
                redisUtil.delete(userId);
            } else {
                throw new BusinessException(UserResponseEnum.SEND_CODE_FAIL);
            }
            AppSendMsg appSendMsg = new AppSendMsg();
            appSendMsg.setPhone(phone);
            appSendMsg.setMessage(password);
            appSendMsg.setSendTime(LocalDateTime.now());
            appSendMsg.setSendStatus(sendSmsResponse.getCode() == null ? "无状态" : sendSmsResponse.getCode());
            appSendMsgService.save(appSendMsg);
        } catch (ClientException e) {
            e.printStackTrace();
        }
    }


    private User cloneUserBoToUser(String phone, String devCode, UserSet userSet) {
        User user = new User();
        //设置用户id
        user.setId(userSet.getUserId());
        //对密码做处理 SM4加密(SM4_1密码+工作秘钥）
        String secretKey = userSet.getSecretKey();
        Sm4Utils sm4 = new Sm4Utils(secretKey);
        user.setPassword(sm4.encryptData_ECB(userSet.getStandBy() + secretKey));
        //填写一些默认值
        user.setPhone(phone);
        user.setDevCode(devCode);
        user.setName(phone);
        user.setLoginName(phone);
        user.setType(3);
        user.setState(UserState.ENABLE);
        user.setOrigin(UserState.NORMAL_ORIGIN);
        user.setCasualUser(UserType.OFFICIAL);
        user.setPwdState(UserState.NEEDLESS);
        user.setRegisterTime(LocalDateTime.now());
        user.setLoginTime(LocalDateTime.now());
        user.setPwdValidity(LocalDateTime.now());
        user.setLoginErrorTimes(UserState.ERROR_PASSWORD_TIMES);
        user.setReferralCode(PubUtils.randomCode(6));
        user.setSmsNotice(0);
        user.setEmailNotice(0);
        user.setLimitIpStart("0.0.0.0");
        user.setLimitIpEnd("255.255.255.255");
        user.setLimitTime("0-24");
        this.save(user);
        return user;
    }

    /**
     * 用户注册完成后自动登录
     * @param phone 手机号码
     * @return
     */
    public Object autoLogin(String phone) {
        String userUrl = "http://127.0.0.1:10214/oauth/token";
        UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(userUrl)
                .queryParam("grant_type", "sms_code")
                .queryParam("client_id", "njcnapp")
                .queryParam("client_secret", "njcnpqs")
                .queryParam("phone", phone)
                .queryParam("smsCode", "123456789");
        URI uri = builder.build().encode().toUri();
        return Objects.requireNonNull(RestTemplateUtil.post(uri, HttpResult.class).getBody()).getData();
    }

}
