package com.njcn.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
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.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.service.*;
import com.njcn.user.util.SmsApiUtil;
import com.njcn.user.util.SmsUtil;
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 java.time.LocalDateTime;
import java.util.*;

/**
 * 类的介绍：
 *
 * @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 IUserSetService userSetService;
    private final IRoleService roleService;
    private final IUserRoleService userRoleService;
    private final IAppInfoSetService appInfoSetService;
    private final SmsApiUtil smsApiUtil;
    private final ISmsSendService smsSendService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String setMessage(String phone, String devCode, String type) {
        if (!PubUtils.match(PatternRegex.PHONE_REGEX, phone)){
            throw new BusinessException(UserResponseEnum.REGISTER_PHONE_WRONG);
        }
        String msgTemplate = SmsUtil.getMessageTemplate(type);
        String vcode = null;
        try {
            //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_PHONE_NOT_REGISTER);
                    } else {
                        user.setDevCode(devCode);
                        logger.info("更新手机id：" + devCode);
                        this.updateById(user);
                    }
                }
            }
            //开始执行短信发送
            vcode = getMessageCode();
            //开始执行短信发送
            String mobiles = phone;
            String content = SmsUtil.getLianTongMessageTemplate(type, vcode);
            smsSendService.sendSmsWithRetry(mobiles,content,"verify_code");
            String key = RedisKeyEnum.SMS_LOGIN_KEY.getKey() + phone;
            //成功发送短信验证码后，保存进redis
            redisUtil.saveByKeyWithExpire(key, vcode, 300L);
        } catch (Exception e) {
            logger.error("发送短信异常，异常为："+e.getMessage());
            throw new BusinessException(e.getMessage());
        }
        return "OK";
    }

    @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);
        }
        User user = this.lambdaQuery().eq(User::getPhone,phone).one();
        if (!Objects.isNull(user)){
            throw new BusinessException(UserResponseEnum.REGISTER_PHONE_REPEAT);
        }
        judgeCode(phone, code);
        //新增用户配置表
        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.setUserId(newUser.getId());
        appInfoSet.setHarmonicInfo(1);
        appInfoSet.setEventInfo(1);
        appInfoSet.setRunInfo(0);
        appInfoSet.setAlarmInfo(0);
        appInfoSet.setIticFunction(0);
        appInfoSet.setF47Function(0);
        appInfoSetService.save(appInfoSet);
        //发送用户初始密码
        String password = redisUtil.getStringByKey(newUser.getId());
        String content = SmsUtil.getLianTongMessageTemplate("3", password);
        smsSendService.sendSmsWithRetry(phone,content,"verify_code");
        redisUtil.delete(newUser.getId());
        //删除验证码
        deleteCode(phone);
    }

    @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,false);
        user.setPassword(secretPassword);
        user.setPwdValidity(LocalDateTime.now());
        user.setLoginTime(LocalDateTime.now());
        user.setDevCode(devCode);
        this.updateById(user);
        //删除验证码
        deleteCode(phone);
    }

    @Override
    public void resetPsd(String phone, String code, String password, String devCode,String ip) {
        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.forgetPassword(user.getId(), password,user.getLoginName(),ip);
        user.setPassword(secretPassword);
        user.setPwdValidity(LocalDateTime.now());
        user.setLoginTime(LocalDateTime.now());
        user.setDevCode(devCode);
        this.updateById(user);
        //删除验证码
        deleteCode(phone);
    }

    @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 user2 = this.lambdaQuery().eq(User::getId,userId).one();
        user2.setName(phoneNew);
        user2.setLoginName(phoneNew);
        user2.setPhone(phoneNew);
        user2.setDevCode(devCode);
        this.updateById(user2);
        //删除验证码
        deleteCode(phoneNew);
    }

    @Override
    @Transactional(rollbackFor = BusinessException.class)
    public void updateDevCode(String userId, String devCode) {
        LambdaUpdateWrapper<User> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.set(User::getDevCode,null).eq(User::getDevCode,devCode);
        this.update(lambdaUpdateWrapper);

        LambdaUpdateWrapper<User> lambdaUpdateWrapper2 = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper2.set(User::getDevCode,devCode).eq(User::getId,userId);
        this.update(lambdaUpdateWrapper2);
    }


    @Override
    public List<User> getAdminInfo() {
        return this.lambdaQuery().in(User::getType, Arrays.asList(0,1)).ne(User::getState,Arrays.asList(0,3)).list();
    }

    /**
     * 自定义获取验证码，固定为字母和数字的组合
     */
    private String getMessageCode() {
        StringBuilder result = new StringBuilder();
        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.append(numbers[numberIndex]);
        }
        return result.toString();
    }

    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);
        }
    }

    private void deleteCode(String phone) {
        String key = RedisKeyEnum.SMS_LOGIN_KEY.getKey() + phone;
        //存在且正确的验证，用完即删
        redisUtil.delete(key);
    }

    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("用户_" + PubUtils.randomCode(8));
        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;
    }

}
