package com.bonus.core.account.v3.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bonus.common.core.exception.ServiceException;
import com.bonus.core.account.v3.api.vo.AccInfoDetailVO;
import com.bonus.core.account.v3.constants.AccStatusEnum;
import com.bonus.core.account.v3.mapper.AccInfoMapper;
import com.bonus.core.account.v3.metadata.enums.AccWalletIdEnum;
import com.bonus.core.account.v3.model.AccInfo;
import com.bonus.core.account.v3.mq.send.AccSendMq;
import com.bonus.core.account.v3.po.AccInfoUpdatePO;
import com.bonus.core.account.v3.service.AccInfoService;
import com.bonus.core.account.v3.service.AccWalletInfoService;
import com.bonus.core.account.v3.utils.AccUtils;
import com.bonus.core.account.v3.web.dto.AccInfoDetailDTO;
import com.bonus.core.account.v3.web.vo.AccInfoVO;
import com.bonus.core.account.v3.web.vo.AccWalletInfoVO;
import com.bonus.core.account.v4.api.CardInfoServiceV4Api;
import com.bonus.core.account.v4.web.model.AccCard;
import com.bonus.core.customer.api.CustAccTempApi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;

@Service
public class AccInfoServiceImpl extends ServiceImpl<AccInfoMapper, AccInfo> implements AccInfoService {
   private static final Logger log = LoggerFactory.getLogger(AccInfoServiceImpl.class);
   public static final String ACC_NOT_EXITS = "acc_not_exits";
   private static final Long CACHE_EXPIRATION_TIME = 60L;
   @Resource
   @Lazy
   private AccWalletInfoService accWalletInfoService;
   @Resource
   @Lazy
   private CardInfoServiceV4Api cardInfoServiceV4Api;

   @Lazy
   @Resource
   private CustAccTempApi custAccTempApi;

   @Resource
   @Lazy
   private AccSendMq accSendMq;

   @Override
   public AccInfoDetailVO getAccInfoDetail(AccInfoDetailDTO content) {
      AccInfoVO accInfo = this.getAccInfoVoByCustId(content.getCustId());
      AccInfoDetailVO accInfoDetailVO = new AccInfoDetailVO();
      BeanUtil.copyProperties(accInfo, accInfoDetailVO, new String[0]);
      accInfoDetailVO.setWalletBal(AccUtils.getWalletBal(accInfo.getWalletInfoList(), AccWalletIdEnum.WALLET.getKey()));
      accInfoDetailVO.setSubsidyBal(AccUtils.getWalletBal(accInfo.getWalletInfoList(), AccWalletIdEnum.SUBSIDY.getKey()));
      accInfoDetailVO.setRedEnvelope(AccUtils.getWalletBal(accInfo.getWalletInfoList(), AccWalletIdEnum.LUCK_MONEY.getKey()));
      accInfoDetailVO.setWalletFreezeBal(AccUtils.getWalletFrozenBal(accInfo.getWalletInfoList(), AccWalletIdEnum.WALLET.getKey()));
      accInfoDetailVO.setSubFreezeBal(AccUtils.getWalletFrozenBal(accInfo.getWalletInfoList(), AccWalletIdEnum.SUBSIDY.getKey()));
      accInfoDetailVO.setAccFreezeBalTotal(accInfo.getAccFreezeBalTotal());
      if (content.getIfQueryCardInfoBoolean()) {
         AccCard accCard = this.cardInfoServiceV4Api.queryOneCardInfoByCustId(accInfo.getCustId());
         if (ObjectUtil.isNotNull(accCard)) {
            accInfoDetailVO.setSerialNum(accCard.getSerialNum());
            accInfoDetailVO.setCardStatus(accCard.getCardStatus());
            accInfoDetailVO.setDeposit(accCard.getDeposit());
            accInfoDetailVO.setProductCost(accCard.getProductCost());
         }
      }
      return accInfoDetailVO;
   }

   @Override
   public void
   updateAccInfo(AccInfoUpdatePO updatePO) {
      AccInfo accInfo = new AccInfo();
      if (!ObjectUtil.isNull(updatePO.getEndDate()) && updatePO.getEndDate().isBefore(LocalDate.now())) {
         accInfo.setAccStatus(AccStatusEnum.OVERDUE.getKey());
      } else {
         accInfo.setAccStatus(AccStatusEnum.NORMAL.getKey());
      }
      //((AccInfoMapper)this.baseMapper).update(accInfo, (Wrapper)((LambdaUpdateWrapper) Wrappers.lambdaUpdate(AccInfo.class).set(AccInfo::getEndDate, updatePO.getEndDate())).eq(AccInfo::getCustId, updatePO.getCustId()));
      this.baseMapper.update(accInfo, Wrappers.lambdaUpdate(AccInfo.class)
              .set(AccInfo::getEndDate, updatePO.getEndDate())
              .eq(AccInfo::getCustId, updatePO.getCustId()));
      this.custAccTempApi.updateAccStatus(Collections.singletonList(updatePO.getCustId()), accInfo.getAccStatus());
      this.accSendMq.accChangeSendHandle(Collections.singletonList(updatePO.getCustId()), accInfo.getAccStatus());
   }

   @Override
   public AccInfoVO getAccInfoVoByCustId(Long custId) {
      log.info("获取账户(钱包)信息,入参={}", custId);
      AccInfoVO accInfoVO = ((AccInfoMapper)this.baseMapper).getAccInfoVOByCustId(custId);
      if (ObjectUtil.isNull(accInfoVO)) {
         throw new ServiceException("账户不存在");
      } else {
         List<AccWalletInfoVO> walletInfoList = this.accWalletInfoService.findAccWalletInfoVOListByCustId(custId);
         this.setAccInfoVODetailList(accInfoVO, walletInfoList);
         log.info("获取账户(钱包)信息,出参={}", JSONUtil.toJsonStr(accInfoVO));
         return accInfoVO;
      }
   }
   protected void setAccInfoVODetailList(AccInfoVO accInfoVO, List<AccWalletInfoVO> walletInfoList) {
      if (ObjectUtil.isNotEmpty(walletInfoList)) {
         accInfoVO.setAccBalTotal((BigDecimal)walletInfoList.stream().map(AccWalletInfoVO::getWalletBal).filter(ObjectUtil::isNotNull).reduce(BigDecimal.ZERO, BigDecimal::add));
         BigDecimal frozenBalanceAll = (BigDecimal)walletInfoList.stream().map(AccWalletInfoVO::getFrozenBalance).filter(ObjectUtil::isNotNull).reduce(BigDecimal.ZERO, BigDecimal::add);
         accInfoVO.setAccFreezeBalTotal(frozenBalanceAll);
         accInfoVO.setAccAllBal(NumberUtil.add(accInfoVO.getAccBalTotal(), accInfoVO.getAccFreezeBalTotal()));
         accInfoVO.setWalletInfoList(walletInfoList);
      }
   }

   @Override
   public void checkAccInfoAndStatus(AccInfoVO accInfoVO){
      if (ObjectUtil.isNull(accInfoVO)) {
         throw new ServiceException("账户不存在");
      } else {
         AccStatusEnum anEnum = AccStatusEnum.getEnum(accInfoVO.getAccStatus());
         if (ObjectUtil.isNull(anEnum)) {
            throw new ServiceException("账户状态异常");
         } else {
            String errorMsg = null;
            switch (anEnum) {
               case DEACTIVATE:
                  errorMsg = "账户已停用";
                  break;
               case CANCEL:
                  errorMsg = "账户已注销";
                  break;
               case OVERDUE:
                  errorMsg = "账户已过期";
                  break;
               default:
                    break;
            }
            if (StrUtil.isNotBlank(errorMsg)) {
               throw new ServiceException(errorMsg);
            }
         }
      }
   }
}
