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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bonus.common.core.exception.ServiceException;
import com.bonus.canteen.core.account.v3.mapper.AccWalletInfoMapper;
import com.bonus.canteen.core.account.v3.model.AccTradeWalletDetail;
import com.bonus.canteen.core.account.v3.model.AccWalletInfo;
import com.bonus.canteen.core.account.v3.po.AccWalletBalanceUpdatePO;
import com.bonus.canteen.core.account.v3.po.AccWalletInfoRechargePO;
import com.bonus.canteen.core.account.v3.service.AccTradeWalletDetailService;
import com.bonus.canteen.core.account.v3.service.AccWalletInfoService;
import com.bonus.canteen.core.account.v3.utils.AccUtils;
import com.bonus.canteen.core.account.v3.web.vo.AccUpdateWalletBalanceVO;
import com.bonus.canteen.core.account.v3.web.vo.AccWalletInfoVO;
import com.bonus.common.houqin.utils.id.Id;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;

@Service
public class AccWalletInfoServiceImpl extends ServiceImpl<AccWalletInfoMapper, AccWalletInfo> implements AccWalletInfoService {
   private static final Logger log = LoggerFactory.getLogger(AccWalletInfoServiceImpl.class);
   @Resource
   @Lazy
   private AccWalletInfoService accWalletInfoService;
   @Resource
   @Lazy
   private AccTradeWalletDetailService accTradeWalletDetailService;
   @Override
   public List<AccWalletInfoVO> findAccWalletInfoVOListByCustId(Long custId) {
      return ((AccWalletInfoMapper)this.baseMapper).queryAccWalletInfoVOListByCustId(custId);
   }


   @Override
   public BigDecimal calculateSubsidyExpirationAmount(Long custId) {
      List<AccWalletInfoVO> walletInfoVOList = ((AccWalletInfoMapper)this.baseMapper).queryAccWalletInfoVOListByCustId(custId);
      BigDecimal subBalAll = (BigDecimal)walletInfoVOList.stream().map((item) -> {
         return item.getWalletBal().add(item.getFrozenBalance());
      }).reduce(BigDecimal.ZERO, BigDecimal::add);
      if (subBalAll.compareTo(BigDecimal.ZERO) > 0) {
         List<AccTradeWalletDetail> detailList = this.accTradeWalletDetailService.listCustMonthAccSubsidyExpirationTrade(custId);
         if (CollUtil.isEmpty(detailList)) {
            return BigDecimal.ZERO;
         } else {
            BigDecimal rechargeAmountSum = (BigDecimal)detailList.stream().map(AccTradeWalletDetail::getAmount).filter(ObjectUtil::isNotNull).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal useAmountSum = (BigDecimal)detailList.stream().map(AccTradeWalletDetail::getUseAmount).filter(ObjectUtil::isNotNull).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal noUseAmount = rechargeAmountSum.subtract(useAmountSum).max(BigDecimal.ZERO);
            return subBalAll.min(noUseAmount);
         }
      } else {
         return BigDecimal.ZERO;
      }
   }

   @Override
   public void updateAccWalletInfoForUse(Long custId, Integer walletId, BigDecimal amount) {
      log.info("[钱包更新]减余额开始,入参={},{},{}", new Object[]{custId, walletId, amount});
      long updateId = Id.next();
      ((AccWalletInfoMapper)this.baseMapper).updateAccWalletInfoForUse(custId, walletId, amount, updateId);
      log.info("[钱包更新]减余额结束");
   }

   @Override
   public AccUpdateWalletBalanceVO updateAccWalletBalance(AccWalletBalanceUpdatePO updatePo) {
      long updateId = Id.next();
      log.info("修改钱包信息->入参:{}", JSONUtil.toJsonStr(updatePo));
      AccUtils.checkAccWalletBalanceUpdateTask(updatePo.getCustId());

      AccUpdateWalletBalanceVO var4;
      try {
         switch (updatePo.getOperationType()) {
            case AUGMENT_BAL:
               ((AccWalletInfoMapper)this.baseMapper).updateAccWalletInfoForRecharge(updatePo.getCustId(), updatePo.getWalletId(), updatePo.getAmount(), updatePo.getLastSubsidyAmount(), updatePo.getLastSubsidyTime(), updateId);
               log.info("[修改钱包信息]增余额结束");
               break;
            case DECREASE_BAL:
               ((AccWalletInfoMapper)this.baseMapper).updateAccWalletInfoForUse(updatePo.getCustId(), updatePo.getWalletId(), updatePo.getAmount(), updateId);
               log.info("[修改钱包信息]减余额结束");
               break;
            case FROZEN_BAL:
               ((AccWalletInfoMapper)this.baseMapper).updateAccWalletInfoForFrozen(updatePo.getCustId(), updatePo.getWalletId(), updatePo.getAmount(), updateId);
               log.info("[修改钱包信息]冻结结束");
               break;
            case UNFROZEN_BAL:
               ((AccWalletInfoMapper)this.baseMapper).updateAccWalletInfoForUnFrozen(updatePo.getCustId(), updatePo.getWalletId(), updatePo.getAmount(), updateId);
               log.info("[修改钱包信息]解冻结束");
            case NO_OPERATION:
               break;
            default:
               throw new ServiceException("修改钱包参数异常");
         }

         var4 = this.getAccWalletBalanceByCustId(updatePo.getCustId());
      } finally {
         AccUtils.unlockAccWalletBalanceUpdate(updatePo.getCustId());
      }
      return var4;
   }

   @Override
   public AccUpdateWalletBalanceVO getAccWalletBalanceByCustId(Long custId) {
      List<AccWalletInfoVO> walletInfoVOList = this.accWalletInfoService.findAccWalletInfoVOListByCustId(custId);
      BigDecimal accAvaiBalTotal = (BigDecimal)walletInfoVOList.stream().map(AccWalletInfoVO::getWalletBal).filter(ObjectUtil::isNotNull).reduce(BigDecimal.ZERO, BigDecimal::add);
      BigDecimal frozenBalanceAll = (BigDecimal)walletInfoVOList.stream().map(AccWalletInfoVO::getFrozenBalance).filter(ObjectUtil::isNotNull).reduce(BigDecimal.ZERO, BigDecimal::add);
      return (new AccUpdateWalletBalanceVO()).setAccBalTotal(accAvaiBalTotal).setAccAllBal(accAvaiBalTotal.add(frozenBalanceAll)).setWalletInfoList(walletInfoVOList);
   }

   public void updateAccWalletInfoForRecharge(AccWalletInfoRechargePO rechargePo) {
      log.info("[钱包更新]增余额开始,入参={}", JSONUtil.toJsonStr(rechargePo));
      long updateId = Id.next();
      ((AccWalletInfoMapper)this.baseMapper).updateAccWalletInfoForRecharge(rechargePo.getCustId(), rechargePo.getWalletId(), rechargePo.getAmount(), rechargePo.getLastSubsidyAmount(), rechargePo.getLastSubsidyTime(), updateId);
      log.info("[钱包更新]增余额结束");
   }

}
