package com.kxs.user.biz.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kxs.common.core.constant.CacheConstants;
import com.kxs.common.core.constant.CommonConstants;
import com.kxs.common.core.constant.SecurityConstants;
import com.kxs.common.core.constant.enums.ErrorTypeEnum;
import com.kxs.common.core.constant.enums.UserStatusEnum;
import com.kxs.common.core.exception.GlobalCustomerException;
import com.kxs.common.core.exception.ValidateCodeException;
import com.kxs.common.core.util.AssertUtil;
import com.kxs.common.core.util.R;
import com.kxs.common.core.util.SpringContextHolder;
import com.kxs.common.core.util.TotalDateUtil;
import com.kxs.common.security.util.SecurityUtils;
import com.kxs.product.api.feign.RemoteKxsProductService;
import com.kxs.product.api.model.KxsMerchant;
import com.kxs.product.api.vo.kxsapp.excel.ExistPayPwdVO;
import com.kxs.store.api.feign.RemoteKxsStoreService;
import com.kxs.store.api.model.KxsWarehouseLimit;
import com.kxs.system.api.feign.RemoteUserMsgService;
import com.kxs.system.api.model.KxsUserMsg;
import com.kxs.system.api.util.MsgTemplateUtil;
import com.kxs.user.api.dto.kxsapp.ConcealParentDTO;
import com.kxs.user.api.dto.kxsapp.app.ForgetPwdDTO;
import com.kxs.user.api.dto.kxsapp.app.MchRegisterDTO;
import com.kxs.user.api.dto.kxsapp.app.RegisterDTO;
import com.kxs.user.api.dto.kxsapp.user.*;
import com.kxs.user.api.model.*;
import com.kxs.user.api.vo.kxsapp.user.*;
import com.kxs.user.api.vo.kxsapp.userLevel.LevelDetailVO;
import com.kxs.user.api.vo.kxsapp.userLevel.LevelsVO;
import com.kxs.user.biz.constant.UserConstants;
import com.kxs.user.biz.constant.enums.KxsUserStatusEnum;
import com.kxs.user.biz.constant.enums.UserErrorTypeEnum;
import com.kxs.user.biz.constant.enums.UserRealStatusEnum;
import com.kxs.user.biz.mapper.*;
import com.kxs.user.biz.service.KxsUserService;
import com.kxs.user.biz.util.SmsUtils;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.RequiredArgsConstructor;
import nonapi.io.github.classgraph.json.JSONUtils;
import org.checkerframework.checker.units.qual.K;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.event.LogoutSuccessEvent;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 用户表(KxsSecurityUser)表服务实现类
 *
 * @author 快秃顶的码农
 * @since 2023-12-05 13:50:24
 */
@Service
@RequiredArgsConstructor
public class KxsUserServiceImpl extends ServiceImpl<KxsUserMapper, KxsUser> implements KxsUserService {

    private final RemoteUserMsgService remoteUserMsgService;

    private final RedisTemplate<String, Object> redisTemplate;

    private final KxsUserAmountMapper userAmountMapper;

    private final OAuth2AuthorizationService authorizationService;

    private final CacheManager cacheManager;

    private final KxsUserRealMapper kxsUserRealMapper;

    private final KxsUserBankMapper kxsUserBankMapper;

    private final RemoteKxsStoreService remoteKxsStoreService;

    private final KxsLeaderMapper kxsLeaderMapper;

    private final KxsPartnerMapper kxsPartnerMapper;

    private final KxsUserPresetLogMapper kxsUserPresetLogMapper;
    private final RemoteKxsProductService remoteKxsProductService;
    @Value("${spring.profiles.active}")
    private String active;

    private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public R register(RegisterDTO registerDTO) {

        //验证码校验
        checkValidateCode(registerDTO.getPhone(), registerDTO.getCode());

        //查询是否注销
        KxsUser isRemove = baseMapper.selectOne(Wrappers.<KxsUser>lambdaQuery().eq(KxsUser::getPhone, registerDTO.getPhone() + "d"));
        if (isRemove != null && isRemove.getUpdateTime() != null && LocalDateTime.now().isBefore(isRemove.getUpdateTime().plusDays(30))) {
            return R.failed(UserErrorTypeEnum.USER_REMOVE.getDescription());
        }
        KxsUser exUser = baseMapper.selectOne(Wrappers.<KxsUser>lambdaQuery().eq(KxsUser::getPhone, registerDTO.getPhone()));
        if (exUser != null) {
            return R.failed(UserErrorTypeEnum.PHONE_IS_EX.getDescription());
        }

        KxsUser kxsUser = new KxsUser();
        BeanUtils.copyProperties(registerDTO, kxsUser);
        kxsUser.setUserCode(null);
        kxsUser.setStatus(UserStatusEnum.NORMAL.getCode());

        //查询上级用户
        KxsUser inviteUser = baseMapper.selectOne(Wrappers.<KxsUser>lambdaQuery().eq(KxsUser::getUserCode, registerDTO.getUserCode()));
        if (inviteUser == null) {
            return R.failed(UserErrorTypeEnum.PARENT_IS_NULL.getDescription());
        }

        kxsUser.setPid(inviteUser.getId());
        //加盐
        String salt = UUID.randomUUID().toString();
        kxsUser.setSalt(salt);
        //登陆密码
        kxsUser.setPassword(ENCODER.encode(registerDTO.getPassword() + salt));
        //保存用户注册信息
        baseMapper.insert(kxsUser);

        //会员序号/推荐码
        String number = String.format("%07d", kxsUser.getId());
        kxsUser.setUserCode(CommonConstants.KXS_USER_NUMBER_PREFIX + number);

        if (CharSequenceUtil.isBlank(inviteUser.getPidPath())) {
            kxsUser.setPidPath("0");
        } else {
            //  拼接上级推荐人的用户ID字符串；如：0,1,2,3,4,5,...用英文逗号隔开
            String superIdTree = (inviteUser.getPidPath().length() == 1 ? inviteUser.getPidPath() + "," : inviteUser.getPidPath()) + inviteUser.getId() + ",";
            kxsUser.setPidPath(superIdTree);
        }
        //更新
        baseMapper.updateById(kxsUser);

        //添加用户账户表
        KxsUserAmount kxsUserAmount = new KxsUserAmount();
        kxsUserAmount.setUserId(kxsUser.getId());
        kxsUserAmount.setId(kxsUser.getId());
        userAmountMapper.insert(kxsUserAmount);

        //初始化用户预发额度表
        KxsWarehouseLimit kxsWarehouseLimit = new KxsWarehouseLimit();
        kxsWarehouseLimit.setUserId(kxsUser.getId());
        R<Boolean> booleanR = remoteKxsStoreService.addUserAdvanceLimit(kxsWarehouseLimit, SecurityConstants.FROM_IN);
        if (!booleanR.getData()) {
            throw new GlobalCustomerException(UserErrorTypeEnum.USER_LIMIT_ERROR.getDescription());
        }

        //发送个人消息
        KxsUserMsg kxsUserMsg = MsgTemplateUtil.newUserPush(inviteUser.getId());
        remoteUserMsgService.pushUserMsg(kxsUserMsg, SecurityConstants.FROM_IN);

        return R.ok();

    }


    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public R mchRegister(MchRegisterDTO registerDTO) {

        //验证码校验
        checkValidateCode(registerDTO.getPhone(), registerDTO.getCode());

        //查询是否注销
        KxsUser isRemove = baseMapper.selectOne(Wrappers.<KxsUser>lambdaQuery().eq(KxsUser::getPhone, registerDTO.getPhone() + "d"));
        if (isRemove != null && isRemove.getUpdateTime() != null && LocalDateTime.now().isBefore(isRemove.getUpdateTime().plusDays(30))) {
            return R.failed(UserErrorTypeEnum.USER_REMOVE.getDescription());
        }
        KxsUser exUser = baseMapper.selectOne(Wrappers.<KxsUser>lambdaQuery().eq(KxsUser::getPhone, registerDTO.getPhone()));
        if (exUser != null) {
            return R.failed(UserErrorTypeEnum.PHONE_IS_EX.getDescription());
        }

        KxsUser kxsUser = new KxsUser();
        BeanUtils.copyProperties(registerDTO, kxsUser);
        kxsUser.setUserCode(null);
        kxsUser.setStatus(UserStatusEnum.NORMAL.getCode());

        //查询上级用户
        KxsUser inviteUser = baseMapper.selectOne(Wrappers.<KxsUser>lambdaQuery().eq(KxsUser::getUserCode, registerDTO.getUserCode()));
        if (inviteUser == null) {
            return R.failed(UserErrorTypeEnum.PARENT_IS_NULL.getDescription());
        }

        kxsUser.setPid(inviteUser.getId());
        //加盐
        String salt = UUID.randomUUID().toString();
        kxsUser.setSalt(salt);
        //登陆密码
        kxsUser.setPassword(ENCODER.encode(registerDTO.getPassword() + salt));
        kxsUser.setIsMerchantMaker(CommonConstants.SUCCESS);
        //保存用户注册信息
        baseMapper.insert(kxsUser);

        //会员序号/推荐码
        String number = String.format("%07d", kxsUser.getId());
        kxsUser.setUserCode(CommonConstants.KXS_USER_NUMBER_PREFIX + number);

        if (CharSequenceUtil.isBlank(inviteUser.getPidPath())) {
            kxsUser.setPidPath("0");
        } else {
            //  拼接上级推荐人的用户ID字符串；如：0,1,2,3,4,5,...用英文逗号隔开
            String superIdTree = (inviteUser.getPidPath().length() == 1 ? inviteUser.getPidPath() + "," : inviteUser.getPidPath()) + inviteUser.getId() + ",";
            kxsUser.setPidPath(superIdTree);
        }
        //更新
        baseMapper.updateById(kxsUser);

        //添加用户账户表
        KxsUserAmount kxsUserAmount = new KxsUserAmount();
        kxsUserAmount.setUserId(kxsUser.getId());
        kxsUserAmount.setId(kxsUser.getId());
        userAmountMapper.insert(kxsUserAmount);

        //初始化用户预发额度表
        KxsWarehouseLimit kxsWarehouseLimit = new KxsWarehouseLimit();
        kxsWarehouseLimit.setUserId(kxsUser.getId());
        R<Boolean> booleanR = remoteKxsStoreService.addUserAdvanceLimit(kxsWarehouseLimit, SecurityConstants.FROM_IN);
        if (booleanR.getStatus() != CommonConstants.SUCCESS || !booleanR.getData()) {
            throw new GlobalCustomerException(UserErrorTypeEnum.USER_LIMIT_ERROR.getDescription());
        }

        //发送个人消息
        KxsUserMsg kxsUserMsg = MsgTemplateUtil.newUserPush(inviteUser.getId());
        remoteUserMsgService.pushUserMsg(kxsUserMsg, SecurityConstants.FROM_IN);

        //给商户添加创客标识，并把商户切换为商户型创客
        KxsMerchant kxsMerchant = new KxsMerchant();
        kxsMerchant.setId(registerDTO.getMchId());
        kxsMerchant.setMakerUserId(kxsUser.getId());
        R res = remoteKxsProductService.changeToMchUser(kxsMerchant, SecurityConstants.FROM_IN);

        if (res.getStatus() != CommonConstants.SUCCESS) {
            throw new GlobalCustomerException(res.getMsg());
        }

        return R.ok();
    }


    @Override
    public Boolean sendCode(String mobile) {

        AssertUtil.isPhone(mobile);

        String key = CacheConstants.DEFAULT_CODE_KEY + mobile;

        Object codeObj = redisTemplate.opsForValue().get(key);

        if (ObjectUtil.isNotEmpty(codeObj)) {
            throw new ValidateCodeException(UserErrorTypeEnum.CODE_NOT_EX.getDescription());
        }
        String code;
        if ("dev".equals(active) || "test".equals(active)) {
            code = "111111";
        } else {
            code = RandomUtil.randomNumbers(Integer.parseInt(UserConstants.CODE_SIZE));
        }
        redisTemplate.opsForValue().set(key, code, UserConstants.CODE_TIME, TimeUnit.SECONDS);
        //发送短信
        if ("prod".equals(active)) {
            SmsUtils.sendCode(mobile, code);
        }
        return Boolean.TRUE;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean forgetPwd(ForgetPwdDTO param) {
        //校验验证码
        checkValidateCode(param.getPhone(), param.getCode());

        //查询用户
        KxsUser user = this.getOne(Wrappers.<KxsUser>lambdaQuery().eq(KxsUser::getPhone, param.getPhone()));
        if (user == null) {
            throw new GlobalCustomerException(UserErrorTypeEnum.USER_NOT_EXIST.getDescription());
        }

        if (CharSequenceUtil.isBlank(user.getSalt())) {
            user.setSalt(UUID.randomUUID().toString());
        }
        //检查重复密码
        if (!Objects.equals(param.getPassword(), param.getConfirmPwd())) {
            throw new GlobalCustomerException(UserErrorTypeEnum.PWD_NOT_EQUALS.getDescription());
        }

        //重置密码
        user.setPassword(ENCODER.encode(param.getPassword() + user.getSalt()));

        //保存新密码
        this.updateById(user);

        return Boolean.TRUE;
    }

    @Override
    public ExistPayPwdVO existPayPwd() {

        KxsUser user = this.getById(SecurityUtils.getUser().getId());
        ExistPayPwdVO existPayPwdVO = new ExistPayPwdVO();
        if (CharSequenceUtil.isBlank(user.getPayPwd())) {
            existPayPwdVO.setPayPwdStatus(0);
            return existPayPwdVO;
        }
        existPayPwdVO.setPayPwdStatus(1);
        return existPayPwdVO;
    }

    @Override
    public Boolean checkPayPwd(String payPwd) {

        KxsUser user = this.getById(SecurityUtils.getUser().getId());

        if (!Objects.equals(user.getPayPwd(), SecureUtil.md5(payPwd + user.getSalt()))) {
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    @Override
    public UserCodeInfoVO userCodeInfo(String userCode) {

        UserCodeInfoVO userCodeInfoVO = new UserCodeInfoVO();

        KxsUser user = this.getOne(Wrappers.<KxsUser>lambdaQuery().eq(KxsUser::getUserCode, userCode));
        if (user == null) {
            return userCodeInfoVO;
        }
        BeanUtils.copyProperties(user, userCodeInfoVO);

        return userCodeInfoVO;
    }

    @Override
    public Boolean checkHandPwd(String handPwd) {

        KxsUser user = this.getById(SecurityUtils.getUser().getId());

        if (!Objects.equals(user.getHandPwd(), SecureUtil.md5(handPwd + user.getSalt()))) {
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    @Override
    public Boolean checkLoginPwd(String password) {

        KxsUser user = this.getById(SecurityUtils.getUser().getId());

        if (!ENCODER.matches(password + user.getSalt(), user.getPassword())) {
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    @Override
    public Boolean logout(String tokenValue) {

        OAuth2Authorization authorization = authorizationService.findByToken(tokenValue, OAuth2TokenType.ACCESS_TOKEN);
        if (authorization == null) {
            return Boolean.TRUE;
        }

        OAuth2Authorization.Token<OAuth2AccessToken> accessToken = authorization.getAccessToken();
        if (accessToken == null || StrUtil.isBlank(accessToken.getToken().getTokenValue())) {
            return Boolean.TRUE;
        }
        // 清空用户信息（立即删除）
        Objects.requireNonNull(cacheManager.getCache(CacheConstants.USER_DETAILS)).evictIfPresent(authorization.getPrincipalName());
        // 清空access token
        authorizationService.remove(authorization);
        // 处理自定义退出事件，保存相关日志
        SpringContextHolder.publishEvent(new LogoutSuccessEvent(new PreAuthenticatedAuthenticationToken(
                authorization.getPrincipalName(), authorization.getRegisteredClientId())));

        return Boolean.TRUE;
    }

    @Override
    public UserInfoVO info() {

        KxsUser user = this.getById(SecurityUtils.getUser().getId());

        KxsUser inviteUser = this.getOne(Wrappers.<KxsUser>lambdaQuery().eq(KxsUser::getId, user.getPid()));

        KxsUserReal userReal = kxsUserRealMapper.selectOne(Wrappers.<KxsUserReal>lambdaQuery().eq(KxsUserReal::getUserId, user.getId()));

        KxsLeader leader = kxsLeaderMapper.selectByLeader(user.getId(), LocalDateTime.now());

        KxsPartner partner = kxsPartnerMapper.selectByPartner(user.getId(), LocalDateTime.now());

        UserInfoVO userInfoVO = new UserInfoVO();
        BeanUtils.copyProperties(user, userInfoVO);

        if (inviteUser != null) {
            userInfoVO.setInviteMobile(inviteUser.getPhone());
            userInfoVO.setInviteName(inviteUser.getUsername());
        }
        if (userReal != null) {
            userInfoVO.setRealTime(userReal.getCreateTime());
        }
        if (leader != null) {
            userInfoVO.setLeaderType(leader.getLeaderType());
            userInfoVO.setLeaderExpDate(leader.getExpiredDate());
        }
        if (partner != null) {
            userInfoVO.setPartnerType(partner.getPartnerType());
        }
        //用户预设职级
        Integer level = baseMapper.selectMaxLevel(SecurityUtils.getUser().getId());
        userInfoVO.setUserLevel(level);
        //用户真实和存量预设职级最大值
        Integer realLevel = baseMapper.selectMaxBeforeLevel(SecurityUtils.getUser().getId());
        userInfoVO.setUserRealLevel(realLevel);
        return userInfoVO;
    }

    @Override
    public R updateArea(UserUpdateAreaDTO param) {

        KxsUser user = this.getById(SecurityUtils.getUser().getId());
        user.setAddress(param.getAddress());
        this.update(Wrappers.<KxsUser>lambdaUpdate().eq(KxsUser::getId, user.getId()).set(KxsUser::getAddress, param.getAddress()));

        return R.ok();

    }

    @Override
    public R modifyPayPwd(KxsUser param) {

        if (StrUtil.isEmpty(param.getPayPwd())) {
            return R.failed("密码不能为空");
        }
        if (param.getPayPwd().length() != 6) {
            return R.failed("密码长度必须为6位");
        }
        KxsUser user = this.getById(SecurityUtils.getUser().getId());
        user.setPayPwd(SecureUtil.md5(param.getPayPwd() + user.getSalt()));

        this.update(Wrappers.<KxsUser>lambdaUpdate().eq(KxsUser::getId, user.getId()).set(KxsUser::getPayPwd, user.getPayPwd()));

        return R.ok();
    }

    @Override
    public R forgetPayPwd(ForgetPayPwdDTO param) {

        checkValidateCode(param.getPhone(), param.getCode());

        KxsUser user = getById(SecurityUtils.getUser().getId());
        KxsUserReal userReal = kxsUserRealMapper.selectOne(Wrappers.<KxsUserReal>lambdaQuery().eq(KxsUserReal::getUserId, SecurityUtils.getUser().getId()));
        if (!param.getUsername().equals(userReal.getRealName())
                || !param.getIdCard().equals(userReal.getIdCard())
                || !param.getPhone().equals(user.getPhone())) {

            return R.failed("用户信息不匹配");
        }
        if (param.getPayPwd().length() != 6) {
            return R.failed("密码长度必须为6位");
        }
        user.setPayPwd(SecureUtil.md5(param.getPayPwd() + user.getSalt()));

        this.update(Wrappers.<KxsUser>lambdaUpdate().eq(KxsUser::getId, user.getId()).set(KxsUser::getPayPwd, user.getPayPwd()));

        return R.ok();
    }

    @Override
    public Object myUserList(Page<KxsUser> page, UserMyUserListDTO param) {

        param.setUserId(SecurityUtils.getUser().getId());
        return baseMapper.myUserList(page, param);
    }

    @Override
    public List<SearchMyUserListVO> searchMyUserList(String keyword) {

        Long userId = SecurityUtils.getUser().getId();
        return baseMapper.searchMyUserList(userId, keyword);
    }

    @Override
    public Object myUserStatistics() {
        Long userId = SecurityUtils.getUser().getId();
        UserMyUserStatisticsVO userMyUserStatisticsVO = new UserMyUserStatisticsVO();
        Long totalCount = baseMapper.selectCount(Wrappers.<KxsUser>query().lambda().eq(KxsUser::getPid, userId));
        userMyUserStatisticsVO.setUserCountTotal(totalCount);
        Long addTotal = baseMapper.selectCount(Wrappers.<KxsUser>query().lambda().eq(KxsUser::getPid, userId).apply("DATE_FORMAT(create_time, '%Y-%m') = DATE_FORMAT(NOW(), '%Y-%m')"));
        userMyUserStatisticsVO.setThisMonthAddTotal(addTotal);
        Long realTotal = baseMapper.selectCount(Wrappers.<KxsUser>query().lambda().eq(KxsUser::getPid, userId).eq(KxsUser::getRealStatus, 1));
        userMyUserStatisticsVO.setRealTotal(realTotal);
        userMyUserStatisticsVO.setNotRealTotal(totalCount - realTotal);
        return userMyUserStatisticsVO;
    }

    @Override
    public R myUserDetail(Integer id) {

        KxsUser user = getById(id);
        UserMyUserDetailVO userMyUserDetailVO = new UserMyUserDetailVO();
        BeanUtils.copyProperties(user, userMyUserDetailVO);
        KxsUserReal kxsUserReal = kxsUserRealMapper.selectOne(Wrappers.<KxsUserReal>query().lambda().eq(KxsUserReal::getUserId, id));
        if (kxsUserReal != null) {
            userMyUserDetailVO.setRealTime(kxsUserReal.getCreateTime());
        }
        return R.ok(userMyUserDetailVO);
    }

    @Override
    public Object verifyUserCode(String userCode) {
        KxsUser one = getOne(Wrappers.<KxsUser>query().lambda().eq(KxsUser::getUserCode, userCode));
        if (one == null) {
            return R.failed("该用户不存在");
        }
        return R.ok(one.getUsername());
    }

    @Override
    public boolean validUserVerify(Long userId) {
        //校验有效创客
        LocalDateTime now = LocalDateTime.now();
        //运营中心校验
        //查询自己当前未过期的运营中心数据
        KxsPartner kxsPartner = kxsPartnerMapper.selectOne(Wrappers.<KxsPartner>query().lambda().eq(KxsPartner::getUserId, userId).gt(KxsPartner::getExpiredDate, now));
        if (kxsPartner != null) {
            return true;
        }
        //查询盟主
        KxsLeader kxsLeader = kxsLeaderMapper.selectOne(Wrappers.<KxsLeader>query().lambda().eq(KxsLeader::getUserId, userId).gt(KxsLeader::getExpiredDate, now));
        if (kxsLeader != null) {
            return true;
        }
        //查询个人名下电签兑换劵+大机兑换券>=3 或 激活POS机数量+激活来客吧商户数量+激活广电卡数量 >3 或 商城下单过指定商品(10-电签机具/广电卡通兑券,11-大POS兑换券,77-来客吧产品组合包A.78-来客吧产品组合包B.79-来客产品组合包C)
        return remoteKxsProductService.verifyUserTicketCountAndShopAndAct(userId, SecurityConstants.FROM_IN);

    }

    @Override
    public Object notRealUser(Page<KxsUser> page) {
        Long id = SecurityUtils.getUser().getId();
        return baseMapper.selectPage(page, Wrappers.<KxsUser>query().lambda().eq(KxsUser::getRealStatus, 0).eq(KxsUser::getPid, id));
    }

    @Override
    public R concealParent(ConcealParentDTO concealParentDTO) {

        Long hideUserId = concealParentDTO.getUserId();
        Integer hiddenLevel = concealParentDTO.getHiddenLevel();
        KxsUser kxsUser = baseMapper.selectById(hideUserId);
        if (kxsUser == null) {
            return R.failed("非法参数,用户不存在");
        }

        return R.ok(update(Wrappers.<KxsUser>lambdaUpdate().set(KxsUser::getHiddenLevel, hiddenLevel).eq(KxsUser::getId, hideUserId)));
    }


    @Override
    public R updatePwd(UserUpdatePwdDTO param) {

        if (!Objects.equals(param.getNewPwd(), param.getConfirmPwd())) {
            return R.failed(UserErrorTypeEnum.PWD_NOT_EQUALS.getDescription());
        }

        KxsUser user = this.getById(SecurityUtils.getUser().getId());

        if (!ENCODER.matches(param.getPassword() + user.getSalt(), user.getPassword())) {
            return R.failed(UserErrorTypeEnum.PWD_ERROR.getDescription());
        }

        this.update(Wrappers.<KxsUser>lambdaUpdate().eq(KxsUser::getId, user.getId()).set(KxsUser::getPassword, ENCODER.encode(param.getNewPwd() + user.getSalt())));

        return R.ok();
    }

    @Override
    public R updateLoginPhone(UserUpdateLoginPhoneDTO param) {

        checkValidateCode(param.getNewPhone(), param.getCode());

        AssertUtil.isPhone(param.getPhone());
        AssertUtil.isPhone(param.getNewPhone());

        KxsUser user = this.getById(SecurityUtils.getUser().getId());
        //判断手机号
        if (!Objects.equals(user.getPhone(), param.getPhone())) {
            return R.failed(UserErrorTypeEnum.PHONE_IS_INCONSISTENT.getDescription());
        }
        //判断密码
        if (!ENCODER.matches(param.getPassword() + user.getSalt(), user.getPassword())) {
            return R.failed(UserErrorTypeEnum.PWD_ERROR.getDescription());
        }

        user.setPhone(param.getNewPhone());
        this.update(Wrappers.<KxsUser>lambdaUpdate().eq(KxsUser::getId, user.getId()).set(KxsUser::getPhone, param.getNewPhone()));

        return R.ok();
    }

    private Boolean httpCheckReal(RealUserDTO param){
        String query = "bankcard=" + param.getBankCode() + "&idcard=" + param.getIdCard() + "&name=" + param.getRealName();
        String url = "https://bankcard3c.shumaidata.com/bankcard3c?" + query;
        //调用三要素认证
        String result = HttpRequest.get(url)
                .header("Authorization", "APPCODE " + "8e5704921ca3422f80f0deb935a7ddc6")
                .timeout(20000)
                .execute().body();
        JSONObject jsonObject = JSON.parseObject(result);
        if(jsonObject == null){
            return Boolean.FALSE;
        }
        if (!"200".equals(jsonObject.getString("code"))){
            return Boolean.FALSE;
        }
        JSONObject data = jsonObject.getObject("data", JSONObject.class);
        if(data != null && !"0".equals(data.getString("result"))){
            throw new GlobalCustomerException(data.getString("desc"));
        }
        return Boolean.TRUE;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R realUser(RealUserDTO param) {

        if (!IdcardUtil.isValidCard(param.getIdCard())) {
            return R.failed(UserErrorTypeEnum.ID_CARD_ERROR.getDescription());
        }
        Long userId = SecurityUtils.getUser().getId();
        KxsUser user = this.getById(userId);

        if(!httpCheckReal(param)){
            return R.failed("实名信息验证不通过");
        }

        //查询实名信息
        KxsUserReal userReal = kxsUserRealMapper.selectOne(Wrappers.<KxsUserReal>lambdaQuery().eq(KxsUserReal::getUserId, user.getId()));
        if (userReal != null) {
            userReal.setRealName(param.getRealName());
            userReal.setIdCard(param.getIdCard());
            userReal.setIdCardFront(param.getIdCardFront());
            userReal.setIdCardHand(param.getIdCardHand());
            userReal.setIdCardRear(param.getIdCardRear());
            kxsUserRealMapper.updateById(userReal);
        } else {
            userReal = new KxsUserReal();
            BeanUtils.copyProperties(param, userReal);
            userReal.setUserId(userId.intValue());
            userReal.setId(userId.intValue());
            kxsUserRealMapper.insert(userReal);
        }
        //查询银行卡信息
        KxsUserBank userBank = kxsUserBankMapper.selectOne(Wrappers.<KxsUserBank>lambdaQuery().eq(KxsUserBank::getUserId, user.getId()));
        if (userBank != null) {
            userBank.setBankPic(param.getBankPic());
            userBank.setBankOpen(param.getBankOpen());
            userBank.setBankCode(param.getBankCode());
            userBank.setBankPhone(param.getBankPhone());
            userBank.setBankName(param.getBankName());
            kxsUserBankMapper.updateById(userBank);
        } else {
            userBank = new KxsUserBank();
            BeanUtils.copyProperties(param, userBank);
            userBank.setUserId(userId.intValue());
            userReal.setId(userId.intValue());
            kxsUserBankMapper.insert(userBank);
        }

        this.update(Wrappers.<KxsUser>lambdaUpdate()
                .eq(KxsUser::getId, user.getId())
                .set(KxsUser::getUsername, param.getRealName())
                .set(KxsUser::getRealStatus, UserRealStatusEnum.YES.getType()));

        return R.ok();
    }

    @Override
    public RealUserInfoVO getRealUserInfo() {

        return baseMapper.findUserRealBankInfo(SecurityUtils.getUser().getId().intValue());
    }

    @Override
    public R handPwd(UserHandPwdDTO param) {

        if (!Objects.equals(param.getHandPwd(), param.getConfirmPwd())) {
            return R.failed(UserErrorTypeEnum.PWD_NOT_EQUALS.getDescription());
        }

        KxsUser user = this.getById(SecurityUtils.getUser().getId());
        String handPwd = SecureUtil.md5(param.getHandPwd() + user.getSalt());

        this.update(Wrappers.<KxsUser>lambdaUpdate().eq(KxsUser::getId, user.getId()).set(KxsUser::getHandPwd, handPwd));

        return R.ok();
    }

    @Override
    public Boolean checkUserInfo(UserCheckUserInfoDTO param) {

        checkValidateCode(param.getPhone(), param.getCode());

        KxsUserReal userReal = kxsUserRealMapper.selectOne(Wrappers.<KxsUserReal>lambdaQuery().eq(KxsUserReal::getUserId, SecurityUtils.getUser().getId()));

        if (!param.getRealName().equals(userReal.getRealName()) || !param.getIdCard().equals(userReal.getIdCard())) {
            return Boolean.FALSE;
        }

        return Boolean.TRUE;
    }

    @Override
    public Boolean updateHead(KxsUser param) {

        return this.update(Wrappers.<KxsUser>lambdaUpdate()
                .eq(KxsUser::getId, SecurityUtils.getUser().getId())
                .set(KxsUser::getAvatar, param.getAvatar()));
    }

    @Override
    public Boolean removeUser() {

        return this.update(Wrappers.<KxsUser>lambdaUpdate()
                .eq(KxsUser::getId, SecurityUtils.getUser().getId())
                .set(KxsUser::getStatus, KxsUserStatusEnum.REMOVE.getType()));
    }

    @Override
    public Boolean checkUserIsChildren(Integer userId, Integer checkUserId) {

        KxsUser user = baseMapper.selectById(checkUserId);
        String pidPath = user.getPidPath();
        //判断是否是下级
        boolean contains = pidPath.contains("," + userId + ",");
        if (!contains) {
            return Boolean.FALSE;
        }

        return Boolean.TRUE;
    }

    @Override
    public RealUserInfoVO loadUserRealBankById(Integer userId) {

        return baseMapper.findUserRealBankInfo(userId);
    }

    @Override
    public LevelDetailVO levelDetail() {

        KxsUser user = this.getById(SecurityUtils.getUser().getId());

        LevelDetailVO levelDetailVO = new LevelDetailVO();
        levelDetailVO.setId(user.getId());
        levelDetailVO.setUsername(user.getUsername());
        levelDetailVO.setAvatar(user.getAvatar());
        //上月业绩等级
        levelDetailVO.setLastLevel(user.getUserLevel());
        //查询用户最高职级
        Integer level = baseMapper.selectMaxLevel(SecurityUtils.getUser().getId());
        levelDetailVO.setUserLevel(level);

        //查询各个职级列表
        ArrayList<LevelsVO> levels = new ArrayList<>();

        //合伙人职级
        KxsPartner kxsPartner = kxsPartnerMapper.selectOne(Wrappers.<KxsPartner>lambdaQuery().eq(KxsPartner::getUserId, user.getId()));
        if (kxsPartner != null) {
            LevelsVO levelsVO = new LevelsVO();
            levelsVO.setLevelName("合伙人职级");
            levelsVO.setLevel(kxsPartner.getPartnerLevel());
            levelsVO.setExpiredDate(kxsPartner.getExpiredDate());
            if (kxsPartner.getExpiredDate().isBefore(LocalDateTime.now())) {
                levelsVO.setStatus(0);
            } else {
                levelsVO.setStatus(1);
            }
            levels.add(levelsVO);
        }
        //盟主职级
        KxsLeader kxsLeader = kxsLeaderMapper.selectOne(Wrappers.<KxsLeader>lambdaQuery().eq(KxsLeader::getUserId, user.getId()));
        if (kxsLeader != null) {
            LevelsVO levelsVO = new LevelsVO();
            levelsVO.setLevelName("盟主职级");
            levelsVO.setLevel(kxsLeader.getLeaderLevel());
            levelsVO.setExpiredDate(kxsLeader.getExpiredDate());
            if (kxsLeader.getExpiredDate().isBefore(LocalDateTime.now())) {
                levelsVO.setStatus(0);
            } else {
                levelsVO.setStatus(1);
            }
            levels.add(levelsVO);
        }
        //预设职级
        KxsUserPresetLog userPresetLog = kxsUserPresetLogMapper.selectOne(Wrappers.<KxsUserPresetLog>lambdaQuery().eq(KxsUserPresetLog::getUserId, user.getId()));
        if (userPresetLog != null) {
            LevelsVO levelsVO = new LevelsVO();
            levelsVO.setLevelName("预设职级");
            levelsVO.setLevel(userPresetLog.getPresetLevel());
            levelsVO.setExpiredDate(userPresetLog.getEndTime());
            levelsVO.setStartTime(userPresetLog.getStartTime());
            if (userPresetLog.getEndTime().isBefore(LocalDateTime.now())) {
                levelsVO.setStatus(0);
            } else {
                levelsVO.setStatus(1);
            }
            levels.add(levelsVO);
        }
        levelDetailVO.setLevels(levels);

        return levelDetailVO;
    }


    public static void main(String[] args) {
        System.out.println(ENCODER.encode("aa121314" + "abc108fa-2060-46fc-b21b-fd5246fecb86"));
        System.out.println(ENCODER.matches("aa121314" + "abc108fa-2060-46fc-b21b-fd5246fecb86", "$2a$10$sBtcVoeOuemMvhVI.OIp3e9LNlamWTOglZdf1AcPIJRY1KKNUvrOW"));
    }


    /**
     * 检查验证码
     *
     * @param mobile 手机号码
     * @param code   密码
     */
    @Override
    public void checkValidateCode(String mobile, String code) {

        if (CharSequenceUtil.isBlank(code)) {
            throw new ValidateCodeException("验证码不能为空");
        }

        String key = CacheConstants.DEFAULT_CODE_KEY + mobile;

        Object codeObj = redisTemplate.opsForValue().get(key);

        if (ObjectUtil.isEmpty(codeObj) || !Objects.equals(code, codeObj)) {
            throw new ValidateCodeException(ErrorTypeEnum.VERIFICATION_CODE_IS_ILLEGAL.getDescription());
        }

        redisTemplate.delete(key);
    }


}

