package com.bonus.canteen.core.customer.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.shaded.javax.annotation.Nullable;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bonus.canteen.core.customer.constants.*;
import com.bonus.canteen.core.customer.po.CustomerNumByOrgIdMapperPO;
import com.bonus.canteen.core.customer.vo.PageCustInfoPhotoVO;
import com.bonus.common.core.constant.CacheConstants;
import com.bonus.common.core.exception.ServiceException;
import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.common.redis.service.RedisService;
import com.bonus.common.houqin.constant.LeCodeUseSceneEnum;
import com.bonus.common.houqin.constant.LeConstants;
import com.bonus.canteen.core.account.v3.api.vo.AccInfoServiceV3Api;
import com.bonus.canteen.core.account.v3.po.AccInfoUpdatePO;
import com.bonus.canteen.core.common.constant.LeMqConstant;
import com.bonus.canteen.core.common.encrypt.SM4EncryptUtils;
import com.bonus.canteen.core.common.utils.LogUtil;
import com.bonus.canteen.core.customer.api.CustCasualApi;
import com.bonus.canteen.core.customer.business.CustInfoBurialPointBusiness;
import com.bonus.canteen.core.customer.dto.*;
import com.bonus.canteen.core.customer.mapper.CustInfoMapper;
import com.bonus.canteen.core.customer.model.CustAccTemp;
import com.bonus.canteen.core.customer.model.CustErrorToLead;
import com.bonus.canteen.core.customer.model.CustInfo;
import com.bonus.canteen.core.customer.model.CustOrgAdjust;
import com.bonus.canteen.core.customer.service.CustAccTempService;
import com.bonus.canteen.core.customer.service.CustDiningPlaceService;
import com.bonus.canteen.core.customer.service.CustInfoCheckService;
import com.bonus.canteen.core.customer.service.CustInfoService;
import com.bonus.canteen.core.customer.utils.CustomerCacheUtil;
import com.bonus.canteen.core.customer.utils.DelFlagEnum;
import com.bonus.canteen.core.customer.vo.CustInfoVo;
import com.bonus.canteen.core.customer.vo.CustNoticeInfoVO;
import com.bonus.canteen.core.customer.vo.CustPayVO;
import com.bonus.canteen.core.device.door.api.DcPushUserDataServiceApi;
import com.bonus.canteen.core.order.mq.MqUtil;
import com.bonus.common.houqin.domain.CustCasual;
import com.bonus.common.houqin.domain.SmsCodeVerifyDTO;
import com.bonus.common.houqin.utils.AesEncryptUtil;
import com.bonus.common.houqin.utils.LeBeanUtil;
import com.bonus.common.houqin.utils.id.Id;
import com.bonus.common.security.utils.SecurityUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Service
public class CustInfoServiceImpl extends ServiceImpl<CustInfoMapper, CustInfo> implements CustInfoService {
    private static final Logger log = LoggerFactory.getLogger(CustInfoServiceImpl.class);
    @Autowired
    private RedisService redisService;
    @Autowired
    @Lazy
    private CustCasualApi custCasualApi;
    @Autowired
    private CustInfoMapper custInfoMapper;

    @Autowired
    @Lazy
    private CustInfoBurialPointBusiness custInfoBurialPointBusiness;
    @Autowired
    @Lazy
    private CustInfoCheckService custInfoCheckService;
    @Autowired
    @Lazy
    private CustDiningPlaceService custDiningPlaceService;
    @Autowired
    @Lazy
    private AccInfoServiceV3Api accInfoServiceV3Api;
    @Autowired
    @Lazy
    private CustAccTempService custAccTempService;

//    @Resource
//    @Lazy
//    private CustOrgAdjustService custOrgAdjustService;


    @Resource
    @Lazy
    private DcPushUserDataServiceApi dcPushUserDataServiceApi;




    @Resource(name = "yunshitangTaskExecutor")
    AsyncTaskExecutor asyncTaskExecutor;

//   @Autowired
//   @Lazy
//   private CustDiningPlaceService custDiningPlaceService;

//   @Value("${customer.h5-login-default-pwd}")
//   private String h5LoginPwd;

   @Override
   public CustInfoVo queryCustInfoDetail(CustInfo custInfo, Integer sourceType) {
      CustInfoVo result = this.getNormalCustInfoDetail(custInfo, sourceType);
      if (ObjectUtil.isNotNull(result)) {
         if (LeConstants.DATA_DEFAULT_INTEGER.equals(result.getSex())) {
            result.setSex((Integer)null);
         }

         if (LeConstants.DATA_DEFAULT_INTEGER.equals(result.getMaritalStatus())) {
            result.setMaritalStatus((Integer)null);
         }
      }

      return this.processCustomerDetailReturnData(result);
   }


   @Nullable
      protected CustInfoVo processCustomerDetailReturnData(CustInfoVo result) {
      if (ObjectUtil.isNull(result)) {
         return result;
      } else {
         if (ObjectUtil.isNotNull(result.getBirthday())) {
            result.setAge(CustAgeEnum.getAge(result.getBirthday()));
         }

         //里面有mqtt相关代码  先注释
//         JsonNode jsonNode = (JsonNode)this.custDiningPlaceService.getDiningPlaceMapByCustIds(Collections.singletonList(result.getCustId())).get(result.getCustId());
//         if (ObjectUtil.isNotEmpty(jsonNode)) {
//            result.setDiningPlace(jsonNode);
//         }

         return result;
      }
   }

   protected CustInfoVo getNormalCustInfoDetail(CustInfo custInfo, Integer sourceType) {
       custInfo.setCustState(PersonalStatusEnum.NORMAL.getKey());
       CustInfoVo custInfoVo = custInfoMapper.queryCustInfoDetail(custInfo);
       if (ObjectUtil.isNotNull(custInfoVo)) {
           return addOrUpdateCustCasual(custInfoVo, sourceType);
       } else {
           return null;
       }
   }

    public CustInfoVo addOrUpdateCustCasual(CustInfoVo custInfoVo, Integer sourceType) {
        Long custId = custInfoVo.getCustId();
        CustCasual custCasual = this.custInfoMapper.selectCustCasualByCustId(custId, sourceType, DelFlagEnum.DEL_FALSE.key());
        String openid;
        if (Objects.isNull(custCasual)) {
            CustCasual insertCasual = new CustCasual();
            openid = IdUtil.simpleUUID();
            insertCasual.setCasualId(Id.next());
            insertCasual.setCasualName(SM4EncryptUtils.sm4Decrypt(custInfoVo.getCustName()));
            insertCasual.setCustId(custInfoVo.getCustId());
            insertCasual.setMobile(SM4EncryptUtils.sm4Decrypt(custInfoVo.getMobile()));
            insertCasual.setOpenid(openid);
            insertCasual.setSourceType(sourceType);
            this.custInfoMapper.addCustCasual(insertCasual);
        } else {
            openid = custCasual.getOpenid();
            if (StringUtils.isBlank(openid)) {
                openid = IdUtil.simpleUUID();
                this.custInfoMapper.updateCustCasual(custCasual);
            }
        }

        custInfoVo.setOpenid(openid);
        custInfoVo.setCustName(SM4EncryptUtils.sm4Decrypt(custInfoVo.getCustName()));
        custInfoVo.setMobile(SM4EncryptUtils.sm4Decrypt(custInfoVo.getMobile()));
        return custInfoVo;
    }



    @Override
    public AjaxResult custChangePassword(CustChangePasswordDTO content) {
        AjaxResult ajaxResult = new AjaxResult();
        CustInfo custInfoQuery = new CustInfo();
        custInfoQuery.setCustId(content.getCustId());
        CustInfo custInfo = custInfoMapper.selectOne(custInfoQuery);
        if (ObjectUtil.isNull(custInfo)) {
            log.error("小程序修改密码错误：人员不存在:" + String.valueOf(custInfo));
//         throw new ServiceException("小程序修改密码错误：人员不存在");
            ajaxResult.put("msg", "小程序修改密码错误：人员不存在");
            ajaxResult.put("code", "500");
        } else {
            content.setOldPassword(AesEncryptUtil.aesDecode(content.getOldPassword()));
            content.setNewPassword(AesEncryptUtil.aesDecode(content.getNewPassword()));
            String oldPassword = content.getOldPassword();
            String newPassword = content.getNewPassword();
            // 1. 检查密码长度
            log.error("开始验证密码长度");
            if (!isPasswordLengthValid(newPassword)) {
                return AjaxResult.error(500, "密码长度应为6至16位！");
            }
            // 2. 检查密码字符类型
            log.error("开始验证密码字符");
            if (!isPasswordCharacterValid(newPassword)) {
                return AjaxResult.error(500, "密码必须包含大、小字母、数字、特殊字符！");
            }
            // 3. 检查常见弱密码
            log.error("开始验证弱密码片段");
            if (containsWeakPassword(newPassword.toLowerCase())) {
                return AjaxResult.error(500, "密码包含常见的弱密码片段！");
            }
            // 4. 检查连续字符
            log.error("开始验证密码连续字符");
            if (containsConsecutiveCharacters(newPassword.toLowerCase(), 3)) {
                return AjaxResult.error(500, "密码不能包含超过3位连续字符！");
            }
            // 5. 检查新旧密码是否相同
            log.error("开始验证新旧密码");
            if (StringUtils.isNotEmpty(oldPassword) && SecurityUtils.matchesPassword(newPassword, oldPassword)) {
                return AjaxResult.error(500, "新密码不能与原密码相同！");
            }
            if (Objects.equals(oldPassword, newPassword)) {
                log.error("小程序修改密码错误：两次密码不能一致");
                ajaxResult.put("msg", "小程序修改密码错误：两次密码不能一致");
                ajaxResult.put("code", "500");
//            throw new ServiceException("小程序修改密码错误：两次密码不能一致");
            } else {
                BCryptPasswordEncoder bCrypt = new BCryptPasswordEncoder();
                if (!bCrypt.matches(oldPassword, custInfo.getPwd())) {
                    log.error("小程序修改密码错误：原密码不正确");
                    ajaxResult.put("msg", "小程序修改密码错误：原密码不正确");
                    ajaxResult.put("code", "500");
//               throw new ServiceException("小程序修改密码错误：原密码不正确");
                } else {
                    String password = bCrypt.encode(newPassword);
                    custInfo.setPwd(password);
                    custInfoMapper.updateById(custInfo);
                    this.custCasualApi.updateLoginState(content.getCustId(), content.getOpenid());
                    ajaxResult.put("msg", "修改成功");
                    ajaxResult.put("code", "200");
                }
            }
        }
        return ajaxResult;
    }

//    public AjaxResult validatePassword(String oldPassword, String newPassword) {
//        // 1. 检查密码长度
//        log.error("开始验证密码长度");
//        if (!isPasswordLengthValid(newPassword)) {
//            return AjaxResult.error(500, "密码长度应为6至16位！");
//        }
//
//        // 2. 检查密码字符类型
//        log.error("开始验证密码字符");
//        if (!isPasswordCharacterValid(newPassword)) {
//            return AjaxResult.error(500, "密码必须包含大、小字母、数字、特殊字符！");
//        }
//
//        // 3. 检查常见弱密码
//        log.error("开始验证弱密码片段");
//        if (containsWeakPassword(newPassword.toLowerCase())) {
//            return AjaxResult.error(500, "密码包含常见的弱密码片段！");
//        }
//
//        // 4. 检查连续字符
//        log.error("开始验证密码连续字符");
//        if (containsConsecutiveCharacters(newPassword.toLowerCase(), 3)) {
//            return AjaxResult.error(500, "密码不能包含超过3位连续字符！");
//        }
//
//        // 5. 检查新旧密码是否相同
//        log.error("开始验证新旧密码");
//        if (StringUtils.isNotEmpty(oldPassword) && SecurityUtils.matchesPassword(newPassword, oldPassword)) {
//            return AjaxResult.error(500, "新密码不能与原密码相同！");
//        }
//
//        log.error("完成密码复杂度验证");
//        return AjaxResult.success();
//    }

    private boolean isPasswordLengthValid(String password) {
        return password.length() >= 6 && password.length() <= 16;
    }

    private boolean isPasswordCharacterValid(String password) {
        boolean hasUpperCase = false, hasLowerCase = false, hasDigit = false, hasSpecialChar = false;

        for (char c : password.toCharArray()) {
            if (Character.isUpperCase(c)) {
                hasUpperCase = true;
            }
            if (Character.isLowerCase(c)) {
                hasLowerCase = true;
            }
            if (Character.isDigit(c)) {
                hasDigit = true;
            }
            if ("!@#$%^&*()-_=+[{]};:'\",<.>/?".indexOf(c) >= 0) {
                hasSpecialChar = true;
            }
        }

        if (!hasUpperCase) {
            return false;
        }
        if (!hasLowerCase) {
            return false;
        }
        if (!hasDigit) {
            return false;
        }
        return !(true && !hasSpecialChar);
    }

    private boolean containsWeakPassword(String password) {
        Set<String> weakPasswords = new HashSet<>(Arrays.asList("111",
                "888",
                "123",
                "234",
                "345",
                "456",
                "567",
                "678",
                "789",
                "1234",
                "2345",
                "3456",
                "4567",
                "5678",
                "6789",
                "abc",
                "abcd",
                "abcde",
                "abcdef",
                "abcdefg",
                "qwe",
                "qwer",
                "qwert",
                "qwerty",
                "asdf",
                "asdfg",
                "asdfgh",
                "password",
                "passw0rd",
                "letmein",
                "welcome",
                "admin",
                "user",
                "test",
                "pass",
                "root",
                "login"));
        for (String weakPwd : weakPasswords) {
            if (password.contains(weakPwd)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 检查密码中是否包含超过 n 个连续相同字符、连续递增/递减的数字或字母（不区分大小写）
     */
    private boolean containsConsecutiveCharacters(String password, int n) {
        // 检查连续相同字符
        n = n + 1;
        for (int i = 0; i <= password.length() - n; i++) {
            boolean consecutiveSameChar = true;
            for (int j = 1; j < n; j++) {
                if (password.charAt(i + j) != password.charAt(i)) {
                    consecutiveSameChar = false;
                    break;
                }
            }
            if (consecutiveSameChar) {
                return true; // 包含超过 n 个连续相同字符
            }
        }

        // 检查连续递增或递减的数字
        for (int i = 0; i <= password.length() - n; i++) {
            boolean consecutiveIncreasing = true;
            boolean consecutiveDecreasing = true;
            for (int j = 1; j < n; j++) {
                char currentChar = password.charAt(i);
                char nextChar = password.charAt(i + j);

                // 检查数字递增或递减
                if (Character.isDigit(currentChar) && Character.isDigit(nextChar)) {
                    if (nextChar != currentChar + j) {
                        consecutiveIncreasing = false;
                    }
                    if (nextChar != currentChar - j) {
                        consecutiveDecreasing = false;
                    }
                } else {
                    consecutiveIncreasing = false;
                    consecutiveDecreasing = false;
                    break;
                }
            }
            if (consecutiveIncreasing || consecutiveDecreasing) {
                return true; // 包含超过 n 个递增或递减的连续数字
            }
        }

        // 检查连续递增或递减的字母（不区分大小写）
        for (int i = 0; i <= password.length() - n; i++) {
            boolean consecutiveIncreasing = true;
            boolean consecutiveDecreasing = true;
            for (int j = 1; j < n; j++) {
                char currentChar = Character.toLowerCase(password.charAt(i)); // 转为小写
                char nextChar = Character.toLowerCase(password.charAt(i + j)); // 转为小写

                // 检查字母递增或递减
                if (Character.isLetter(currentChar) && Character.isLetter(nextChar)) {
                    if (nextChar != currentChar + j) {
                        consecutiveIncreasing = false;
                    }
                    if (nextChar != currentChar - j) {
                        consecutiveDecreasing = false;
                    }
                } else {
                    consecutiveIncreasing = false;
                    consecutiveDecreasing = false;
                    break;
                }
            }
            if (consecutiveIncreasing || consecutiveDecreasing) {
                // 包含超过 n 个递增或递减的连续字母
                return true;
            }
        }
        // 不包含连续相同字符、数字或字母序列
        return false;
    }


    @Override
    public AjaxResult custForgetPassword(CustForgetPasswordDTO content) {
        AjaxResult ajaxResult = new AjaxResult();
        content.setNewPassword(AesEncryptUtil.aesDecode(content.getNewPassword()));
        SmsCodeVerifyDTO smsCodeVerifyDTO = new SmsCodeVerifyDTO();
        smsCodeVerifyDTO.setTelephoneNumber(content.getMobile());
        smsCodeVerifyDTO.setCode(content.getCode());
        if (!verifySmsCode(smsCodeVerifyDTO, CacheConstants.VERIFICATION_CODE)) {
//            throw new ServiceException("验证码异常");
            ajaxResult.put("msg", "验证码异常");
            ajaxResult.put("code", "500");
        } else {
            CustInfo custInfoQuery = new CustInfo();
            custInfoQuery.setMobile(SM4EncryptUtils.sm4Encryptbyconfig(content.getMobile()));
            CustInfo custInfo = custInfoMapper.selectOne(custInfoQuery);
            if (ObjectUtil.isNull(custInfo)) {
                log.error("修改密码错误：人员不存在:" + custInfo);
//                throw new ServiceException("修改密码错误：人员不存在", RetCodeEnum.PAY_PERSONAL_NO_EXIT.getKey());
                ajaxResult.put("msg", "修改密码错误：人员不存在");
                ajaxResult.put("code", "500");
            } else {
                String newPassword = content.getNewPassword();
                // 1. 检查密码长度
                log.error("开始验证密码长度");
                if (!isPasswordLengthValid(newPassword)) {
                    return AjaxResult.error(500, "密码长度应为6至16位！");
                }
                // 2. 检查密码字符类型
                log.error("开始验证密码字符");
                if (!isPasswordCharacterValid(newPassword)) {
                    return AjaxResult.error(500, "密码必须包含大、小字母、数字、特殊字符！");
                }
                // 3. 检查常见弱密码
                log.error("开始验证弱密码片段");
                if (containsWeakPassword(newPassword.toLowerCase())) {
                    return AjaxResult.error(500, "密码包含常见的弱密码片段！");
                }
                // 4. 检查连续字符
                log.error("开始验证密码连续字符");
                if (containsConsecutiveCharacters(newPassword.toLowerCase(), 3)) {
                    return AjaxResult.error(500, "密码不能包含超过3位连续字符！");
                }
                BCryptPasswordEncoder bCrypt = new BCryptPasswordEncoder();
                String password = bCrypt.encode(newPassword);
                custInfoMapper.updateCustPwdByCustId(password, custInfo.getCustId());
                ajaxResult.put("msg", "修改成功");
                ajaxResult.put("code", "200");
            }
        }
        return ajaxResult;
    }

    @Override
    public AjaxResult rebindMobile(CustBindMobileDTO content, Integer sourceType) {
        AjaxResult ajaxResult = new AjaxResult();
        SmsCodeVerifyDTO smsCodeVerifyDTO = new SmsCodeVerifyDTO();
        smsCodeVerifyDTO.setTelephoneNumber(content.getNewMobile());
        smsCodeVerifyDTO.setCode(content.getCode());
        if (!verifySmsCode(smsCodeVerifyDTO, CacheConstants.VERIFICATION_CODE)) {
            ajaxResult.put("msg", "验证码异常");
            ajaxResult.put("code", "500");
        } else {
            CustInfo custInfoQuery = new CustInfo();
            custInfoQuery.setMobile(SM4EncryptUtils.sm4Encryptbyconfig(content.getOldMobile()));
            CustInfo custInfo = custInfoMapper.selectOne(custInfoQuery);
            if (ObjectUtil.isNull(custInfo)) {
                log.error("修改密码错误：人员不存在:" + custInfo);
                ajaxResult.put("msg", "修改密码错误：人员不存在");
                ajaxResult.put("code", "500");
            } else {
                custInfo.setMobile(SM4EncryptUtils.sm4Encryptbyconfig(content.getNewMobile()));
                custInfoMapper.updateById(custInfo);
                CustCasual custCasual = this.custInfoMapper.selectCustCasualByCustId(custInfo.getCustId(), sourceType, DelFlagEnum.DEL_FALSE.key());
                if (Objects.nonNull(custCasual)) {
                    custCasual.setMobile(content.getNewMobile());
                    this.custInfoMapper.updateCustCasual(custCasual);
                }
                ajaxResult.put("msg", "修改成功");
                ajaxResult.put("code", "200");
            }
        }
        return ajaxResult;
    }

    public boolean verifySmsCode(SmsCodeVerifyDTO smsCodeVerifyDTO, String cacheKey) {
        String key = cacheKey + smsCodeVerifyDTO.getTelephoneNumber();
        String code = redisService.getCacheObject(key); //RedisUtil.getString(key);
        log.info("redis缓存验证码code : {}", code);
        return ObjectUtil.isNotEmpty(code) && ObjectUtil.equal(code, smsCodeVerifyDTO.getCode());
    }

    @Override
    public String getOrderQRCode(Integer sourceType, String paramValue) {
        String stime = String.valueOf(System.currentTimeMillis());
        return "xnzn{\"s\":" + sourceType + ",\"y\":" + LeCodeUseSceneEnum.PAY.key() + ",\"p\":\"" + paramValue + "\",\"t\":" + "\"" + stime + "\"}";
    }

    public static void assembleErrInfo(List<CustErrorToLead> custErrorToLeadList, CustAccExcelModel temp, String msg) {
        CustErrorToLead custErrorToLead = new CustErrorToLead();
        custErrorToLead.setErrorId(Id.next());
        custErrorToLead.setCustName(temp.getCustName());
        custErrorToLead.setMobile(temp.getMobile());
        custErrorToLead.setCustNum(temp.getCustNum());
        custErrorToLead.setErrorMsg(msg);
        custErrorToLead.setErrorDate(LocalDate.now());
        custErrorToLeadList.add(custErrorToLead);
    }


    protected CustInfo update(@NotNull CustInfoModel infoModel) {
        CustInfo custInfo = new CustInfo();
        BeanUtil.copyProperties(infoModel, custInfo, new String[0]);
        if (ObjectUtil.isNotEmpty(custInfo.getBirthday())) {
            custInfo.setAge(DateUtil.ageOfNow(custInfo.getBirthday().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))));
        }

        if (CharSequenceUtil.isNotBlank(custInfo.getMobile()) && custInfo.getMobile().length() > 4) {
            custInfo.setMobileSuffix(custInfo.getMobile().substring(custInfo.getMobile().length() - 4));
        }

        if (ObjectUtil.isNotEmpty(custInfo.getCustName())) {
            custInfo.setCustNameLike(custInfo.getCustName());
        }
        BCryptPasswordEncoder bCrypt = new BCryptPasswordEncoder();
        custInfo.setPwd(bCrypt.encode(custInfo.getPwd()));

        custInfo.setPsnType(custInfo.getPsnType()).setBirthday(custInfo.getBirthday()).setAge(custInfo.getAge()).setPlaceId(custInfo.getPlaceId() == null ? CustConstant.DATA_DEFAULT_LONG : custInfo.getPlaceId()).setSex((Integer)Optional.ofNullable(infoModel.getSex()).orElse(3));
       // ((CustInfoMapper)this.baseMapper).update(custInfo, (Wrapper)(new LambdaUpdateWrapper(CustInfo.class)).eq(CustInfo::getCustId, infoModel.getCustId()));
        custInfoMapper.update(custInfo, new LambdaUpdateWrapper<CustInfo>().eq(CustInfo::getCustId, infoModel.getCustId()));
        return custInfo;
    }
    protected void unbindPlace(Long placeId) {
        if (!ObjectUtil.isNull(placeId) && !CustConstant.DATA_DEFAULT_LONG.equals(placeId)) {
            //((CustInfoMapper)this.baseMapper).update((Object)null, (Wrapper)((LambdaUpdateWrapper) Wrappers.lambdaUpdate().eq(CustInfo::getPlaceId, placeId)).set(CustInfo::getPlaceId, CustConstant.DATA_DEFAULT_LONG));
            custInfoMapper.update(null, Wrappers.<CustInfo>lambdaUpdate().eq(CustInfo::getPlaceId, placeId).set(CustInfo::getPlaceId, CustConstant.DATA_DEFAULT_LONG));
        }
    }

    protected void saveOrgAdjust(CustInfoModel newcustInfoModel) {
        Long newOrgId = newcustInfoModel.getOrgId();
        Long oldOrgId = this.getOrgIdBuCustId(newcustInfoModel.getCustId());
        if (ObjectUtil.notEqual(newOrgId, oldOrgId)) {
            CustOrgAdjust custOrgAdjust = new CustOrgAdjust();
            custOrgAdjust.setCustId(newcustInfoModel.getCustId());
            custOrgAdjust.setAdjustDate(LocalDate.now());
            custOrgAdjust.setOldOrgId(oldOrgId);
            custOrgAdjust.setNewOrgId(newOrgId);
        //    this.custOrgAdjustService.addRecord(custOrgAdjust);
            CustomerCacheUtil.deleteCustomerNumBelongOrgMapCache();
        }
    }

    protected Long getOrgIdBuCustId(Long custId) {
        if (ObjectUtil.isNull(custId)) {
            throw new ServiceException("customer.id.nonNull");
        } else {
           // return ((CustInfo)((CustInfoMapper)this.baseMapper).selectOne((Wrapper)Wrappers.lambdaQuery(CustInfo.class).select(new SFunction[]{CustInfo::getOrgId}).eq(CustInfo::getCustId, custId))).getOrgId();
            return custInfoMapper.selectOne(Wrappers.<CustInfo>lambdaQuery()
                            .select(CustInfo::getOrgId)
                            .eq(CustInfo::getCustId, custId))
                    .getOrgId();
        }
    }

    protected void notifyOtherModules(Long custId, LeMqConstant.DataChangeType dataChangeType) {
        String currentTraceId = LogUtil.getCurrentTraceId();
        log.info("通知其他模块人员变动开始");
        log.info("类型[{}]", dataChangeType);
        CompletableFuture.runAsync(() -> {
            LogUtil.putLogTraceId(currentTraceId);
            if (LeMqConstant.DataChangeType.ADD.equals(dataChangeType)) {
                this.dcPushUserDataServiceApi.addUser(custId);
                log.info("通知门禁结束");
            } else if (LeMqConstant.DataChangeType.UPDATE.equals(dataChangeType)) {
                this.dcPushUserDataServiceApi.editUser(custId);
                log.info("通知门禁结束");
            } else if (LeMqConstant.DataChangeType.REMOVE.equals(dataChangeType)) {
                this.dcPushUserDataServiceApi.deleteUser(custId);
                log.info("通知门禁结束");
            }

            this.custInfoBurialPointBusiness.didNotifyOtherModules(custId, dataChangeType);
        }, this.asyncTaskExecutor);
    }

    @Override
    public void updateDetailCustInfo(CustInfoModel infoModel) {
        this.custInfoBurialPointBusiness.willAddOrUpdateCust(infoModel);
        this.custInfoCheckService.checkCustInfoOnlyAndSetRedundantData(infoModel);
        this.unbindPlace(infoModel.getPlaceId());
        this.saveOrgAdjust(infoModel);
        CustInfo custInfo = this.update(infoModel);
        this.custDiningPlaceService.save(infoModel.getCustId(), infoModel.getDiningPlace());
        this.accInfoServiceV3Api.updateAccInfo(AccInfoUpdatePO.builder().custId(infoModel.getCustId()).endDate(infoModel.getAccEndDate()).build());
        CustAccTemp custAccTemp = new CustAccTemp();
        LeBeanUtil.copyProperties(custInfo, custAccTemp);
        this.custAccTempService.update(custAccTemp);
        MqUtil.sendDataChange(infoModel.getCustId(), LeMqConstant.DataChangeType.UPDATE, LeMqConstant.Topic.DATA_CHANGE_CUSTOMER);
        this.notifyOtherModules(infoModel.getCustId(), LeMqConstant.DataChangeType.UPDATE);
        this.custInfoBurialPointBusiness.willAddOrUpdateCustAfter(infoModel, false);
    }


    @Override
    public CustInfoVo queryCustInfo(CustInfoDTO record) {
        if (Objects.isNull(record.getCustState())) {
            record.setCustState(PersonalStatusEnum.NORMAL.getKey());
        }
        return this.baseMapper.queryCustInfo(record);
    }

    @Override
    public List<Long> selectCustIdByCondition(List<Long> orgIdList, List<Integer> psnTypeList, LocalDateTime crtime) {
        return null;
    }

    @Override
    public List<Long> selectCustIdOrCondition(List<Long> orgIdList, List<Integer> psnTypeList) {
        return null;
    }



    @Override
    public void updateCustName(Long custId, String custName) {

    }

    @Override
    public List<CustNoticeInfoVO> queryCustNoticeInfoList(CustNoticeInfoPageDTO queryDTO) {
        return null;
    }

    @Override
    public CustInfo addCustForDing(AddCustForDingDTO dto) {
        return null;
    }

    @Override
    public void updateCustForDing(AddCustForDingDTO dto) {

    }

    @Override
    public Long customerCountByParams(Collection<Integer> custStates, Collection<Long> orgIds) {
        return null;
    }

    @Override
    public Map<Long, Integer> getCustomerNumBelongOrg() {
        List<CustomerNumByOrgIdMapperPO> customerNumByOrgIdList = ((CustInfoMapper)this.baseMapper).getCustomerNumByOrgIdList((Collection)null);
        return (Map)(CollUtil.isEmpty(customerNumByOrgIdList) ? new HashMap() : (Map)customerNumByOrgIdList.stream().collect(Collectors.toMap(CustomerNumByOrgIdMapperPO::getOrgId, CustomerNumByOrgIdMapperPO::getCustomerNum)));
    }

    @Override
    public void updateCustomersOrgNumAndOrgFullName(Collection<Long> orgIdList) {

    }

    @Override
    public boolean existsNormalCustNum(String custNum, Long excludeCustId) {
        return false;
    }

    @Override
    public boolean existsNormalCustMobile(String mobile, Long excludeCustId) {
        return false;
    }

    @Override
    public Map<String, Long> getAllNormalCustNumValueMap() {
        return null;
    }

    @Override
    public void updateOrgNoAdjuestLog(Collection<Long> custIds, Long orgId) {
//        if (!CollUtil.isEmpty(custIds) && !ObjectUtil.isNull(orgId)) {
//            QueryOrgsBasicInfoPO queryOrgsBasicInfoPO = (new QueryOrgsBasicInfoPO()).setOrgIds(Collections.singleton(orgId)).setDelFlags(Collections.singleton(DelFlagEnum.DEL_FALSE.key()));
//            List<OrgBasicInfoVO> orgBasicInfoVOList = this.custOrgService.listOrgBasicInfoByParams(queryOrgsBasicInfoPO);
//            if (CollUtil.isEmpty(orgBasicInfoVOList)) {
//                throw new ServiceException("customer.org.org.inexists");
//            } else {
//                OrgBasicInfoVO orgBasicInfoVO = (OrgBasicInfoVO)orgBasicInfoVOList.get(0);
//                //((CustInfoMapper)this.baseMapper).update((Object)null, (Wrapper)((LambdaUpdateWrapper)((LambdaUpdateWrapper)((LambdaUpdateWrapper)Wrappers.lambdaUpdate().in(CustInfo::getCustId, custIds)).set(CustInfo::getOrgId, orgBasicInfoVO.getOrgId())).set(CustInfo::getOrgNum, orgBasicInfoVO.getOrgNum())).set(CustInfo::getOrgFullName, orgBasicInfoVO.getOrgFullName()));
//                ((CustInfoMapper)this.baseMapper).update(null, Wrappers.<CustInfo>lambdaUpdate()
//                        .in(CustInfo::getCustId, custIds)
//                        .set(CustInfo::getOrgId, orgBasicInfoVO.getOrgId())
//                        .set(CustInfo::getOrgNum, orgBasicInfoVO.getOrgNum())
//                        .set(CustInfo::getOrgFullName, orgBasicInfoVO.getOrgFullName()));
//                CustomerCacheUtil.deleteCustomerNumBelongOrgMapCache();
//                this.batchNotifyOtherModules(new HashSet(custIds), LeMqConstant.DataChangeType.UPDATE);
//            }
//        }
    }


    protected void batchNotifyOtherModules(Set<Long> custIds, LeMqConstant.DataChangeType dataChangeType) {
        String currentTraceId = LogUtil.getCurrentTraceId();
        log.info("[{}]批量人员通知其他模块开始", dataChangeType);
        CompletableFuture.runAsync(() -> {
            LogUtil.putLogTraceId(currentTraceId);
            custIds.forEach((custId) -> {
                if (LeMqConstant.DataChangeType.ADD.equals(dataChangeType)) {
                    this.dcPushUserDataServiceApi.addUser(custId);
                    log.info("[{}]通知门禁结束", dataChangeType);
                } else if (LeMqConstant.DataChangeType.UPDATE.equals(dataChangeType)) {
                    this.dcPushUserDataServiceApi.editUser(custId);
                    log.info("[{}]通知门禁结束", dataChangeType);
                } else if (LeMqConstant.DataChangeType.REMOVE.equals(dataChangeType)) {
                    this.dcPushUserDataServiceApi.deleteUser(custId);
                    log.info("[{}]通知门禁结束", dataChangeType);
                }

                this.custInfoBurialPointBusiness.didNotifyOtherModules(custId, dataChangeType);
            });
        }, this.asyncTaskExecutor);
    }



    @Override
    public CustPayVO getCustPayVO(CustPayDTO custPayDTO) {
        log.info("获取支付所需人员，custPayDTO={}", JSONUtil.toJsonStr(custPayDTO));
        if (!Objects.isNull(custPayDTO) && (!CharSequenceUtil.isBlank(custPayDTO.getSerialNum()) || !CharSequenceUtil.isBlank(custPayDTO.getOpenid()) || !Objects.isNull(custPayDTO.getCustId()))) {
            List<CustPayVO> custPayVoList = ((CustInfoMapper)this.baseMapper).getCustPayVO(custPayDTO);
            if (CollUtil.isEmpty(custPayVoList)) {
                throw new ServiceException("人员不存在");
            } else {
                List<CustPayVO> custList = (List)custPayVoList.stream().filter((e) -> {
                    return PersonalStatusEnum.NORMAL.getKey().equals(e.getCustState());
                }).collect(Collectors.toList());
                if (CollUtil.isEmpty(custList)) {
                    throw new ServiceException("customer.customer.cancel");
                } else {
                    if (custList.size() > 1) {
                        log.info("查询记录:{}", JSON.toJSONString(custPayVoList));
                    }

                    log.info("获取支付所需人员{}", ((CustPayVO)custList.get(0)).getCustName());
                    return (CustPayVO)custList.get(0);
                }
            }
        } else {
            throw new ServiceException("参数错误！");
        }
    }

    @Override
    public void updateCustPhotoUrl(Long custId, String cutPhotoUrl) {
        ((CustInfoMapper)this.baseMapper).update(null, Wrappers.<CustInfo>lambdaUpdate()
                .eq(CustInfo::getCustId, custId)
                .set(CustInfo::getCustPhotoUrl, cutPhotoUrl));
    }

    public List<PageCustInfoPhotoVO> pageCustInfoPhoto(CustInfoParam infoParam) {
        this.convertQueryParam(infoParam);
        List<PageCustInfoPhotoVO> pageCustInfoPhotoVoPage = ((CustInfoMapper)this.baseMapper).pageCustInfoPhoto(infoParam);
        this.processCustomerPageReturnData(pageCustInfoPhotoVoPage);
        this.custInfoBurialPointBusiness.willQueryCustInfoByPage(infoParam, pageCustInfoPhotoVoPage);
        return pageCustInfoPhotoVoPage;
    }

    protected void convertQueryParam(CustInfoParam infoParam) {
        if (CharSequenceUtil.isNotBlank(infoParam.getShape())) {
            infoParam.setShape(LeBeanUtil.fieldLikeHandle(infoParam.getShape()));
        }

        if (CharSequenceUtil.isNotBlank(infoParam.getChronicIds())) {
            infoParam.setChronicIds(LeBeanUtil.fieldLikeHandle(infoParam.getChronicIds()));
        }

        infoParam.setPhotoType(PhotoTypeEnum.PHOTO.getKey());
        infoParam.setCustState(PersonalStatusEnum.NORMAL.getKey());
    }

    @Nullable
    protected List<PageCustInfoPhotoVO> processCustomerPageReturnData(List<PageCustInfoPhotoVO> custInfoVo) {
        if (CollUtil.isEmpty(custInfoVo)) {
            return custInfoVo;
        } else {
            Iterator var2 = custInfoVo.iterator();

            while(var2.hasNext()) {
                PageCustInfoPhotoVO custInfoPhotoVO = (PageCustInfoPhotoVO)var2.next();
                if (ObjectUtil.isNull(custInfoPhotoVO.getFeaturesBuildStatus())) {
                    custInfoPhotoVO.setFeaturesBuildStatus(FeaturesBuildStatusEnum.UN_CREATE.getKey());
                }
            }

            return custInfoVo;
        }
    }
}
