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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.bonus.common.core.exception.ServiceException;
import com.bonus.core.account.v3.constants.AccRechargeOperateEnum;
import com.bonus.core.account.v3.constants.AccSubClearOpSourceEnum;
import com.bonus.core.account.v3.constants.AccTradeTypeEnum;
import com.bonus.core.account.v3.constants.AccUpdateWalletOperateEnum;
import com.bonus.core.account.v3.dto.AccWalletUpdateDTO;
import com.bonus.core.account.v3.metadata.enums.AccWalletIdEnum;
import com.bonus.core.account.v3.model.AccTradeUseAmountHist;
import com.bonus.core.account.v3.model.AccTradeWalletDetail;
import com.bonus.core.account.v3.mq.send.AccSendMq;
import com.bonus.core.account.v3.mq.send.dto.RepAccMqDTO;
import com.bonus.core.account.v3.mq.send.model.RepAccMqDetailModel;
import com.bonus.core.account.v3.mq.send.model.RepAccMqModel;
import com.bonus.core.account.v3.utils.AccUtils;
import com.bonus.core.account.v3.web.vo.AccInfoVO;
import com.bonus.core.common.utils.LogUtil;
import com.bonus.core.common.utils.TenantContextHolder;
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.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class AccSubBusinessService {
   private static final Logger log = LoggerFactory.getLogger(AccSubBusinessService.class);
   @Resource(
      name = "yunshitangTaskExecutor"
   )
   @Lazy
   private AsyncTaskExecutor asyncTaskExecutor;
   @Autowired
   private AccTradeWalletDetailService accTradeWalletDetailService;
   @Autowired
   private AccTradeUseAmountHistService accTradeUseAmountHistService;


   public void subsidyChangeBusiness(List<RepAccMqModel> resultList) {
      if (!CollUtil.isEmpty(resultList)) {
         this.asyncTaskExecutor.execute(() -> {
            try {
               LogUtil.generateNewLogTraceId();
               log.info("[补贴变动]修改存在补贴有效期的使用金额开始");
               this.subsidyChangeBusinessHandle(resultList);
            } catch (Exception var3) {
               log.error("[补贴变动]修改存在补贴有效期的金额,错误", var3);
            }

         });
      }
   }

   protected void subsidyChangeBusinessHandle(List<RepAccMqModel> resultList) {
      List<Long> custIdList = this.accTradeWalletDetailService.selectCustIdForSubsidyExpireTime(LocalDateTime.now());
      resultList.forEach((item) -> {
         if (AccTradeTypeEnum.listExpiredSubsidyIncome().contains(item.getFlowType())) {
            this.expiredSubsidyIncomeBusiness(item);
         } else if (AccTradeTypeEnum.listExpiredSubsidyExpend().contains(item.getFlowType()) && CollUtil.isNotEmpty(custIdList)) {
            this.expiredSubsidyExpendBusiness(custIdList, item);
         }

      });
      log.info("[补贴变动]修改存在补贴有效期的使用金额结束");
   }

   protected void expiredSubsidyExpendBusiness(List<Long> custIdList, RepAccMqModel repAccMqModel) {
      if (custIdList.contains(repAccMqModel.getCustId()) && !AccSubClearOpSourceEnum.CLEAR_EXPIRED.getKey().equals(repAccMqModel.getOperateSource())) {
         List<RepAccMqDetailModel> detailModelList = (List)repAccMqModel.getWalletDetail().stream().filter((item) -> {
            return ObjectUtil.isNotNull(item.getWalletId()) && ObjectUtil.equal(item.getWalletId().intValue(), AccWalletIdEnum.SUBSIDY.getKey());
         }).collect(Collectors.toList());
         if (!CollUtil.isEmpty(detailModelList)) {
            Iterator var4 = detailModelList.iterator();

            while(var4.hasNext()) {
               RepAccMqDetailModel repAccMqDetailModel = (RepAccMqDetailModel)var4.next();
               try {
                  this.calculateSubsidyAmount(repAccMqModel.getCustId(), repAccMqDetailModel);
               } catch (Exception var7) {
                  break;
               }
            }

         }
      }
   }

   private void expiredSubsidyIncomeBusiness(RepAccMqModel repAccMqModel) {
      List<RepAccMqDetailModel> detailModelList = (List)repAccMqModel.getWalletDetail().stream().filter((item) -> {
         return ObjectUtil.isNotNull(item.getWalletId()) && ObjectUtil.equal(item.getWalletId().intValue(), AccWalletIdEnum.SUBSIDY.getKey());
      }).collect(Collectors.toList());
      if (!CollUtil.isEmpty(detailModelList)) {
         Iterator var3 = detailModelList.iterator();

         while(true) {
            RepAccMqDetailModel repAccMqDetailModel;
            List accTradeUseAmountHists;
            do {
               if (!var3.hasNext()) {
                  return;
               }

               repAccMqDetailModel = (RepAccMqDetailModel)var3.next();
               accTradeUseAmountHists = this.accTradeUseAmountHistService.canRefundTradeHist(repAccMqModel.getOriginTradeId());
            } while(CollUtil.isEmpty(accTradeUseAmountHists));

            BigDecimal refundAmount = repAccMqDetailModel.getAmount();
            Iterator var7 = accTradeUseAmountHists.iterator();

            while(var7.hasNext()) {
               AccTradeUseAmountHist accTradeUseAmountHist = (AccTradeUseAmountHist)var7.next();
               BigDecimal canRefund = accTradeUseAmountHist.getUseAmount().subtract(accTradeUseAmountHist.getRefundAmount()).min(refundAmount).max(BigDecimal.ZERO);
               if (canRefund.compareTo(BigDecimal.ZERO) > 0) {
                  this.accTradeWalletDetailService.updateExpiredClearTradeUseAmount(accTradeUseAmountHist.getOriginTradeId(), canRefund.multiply(BigDecimal.valueOf(-1L)));
                  this.accTradeUseAmountHistService.updateRefundAmount(accTradeUseAmountHist.getId(), canRefund);
                  AccTradeUseAmountHist accTradeRefundAmountHist = new AccTradeUseAmountHist();
                  accTradeRefundAmountHist.setOriginTradeId(accTradeUseAmountHist.getOriginTradeId());
                  accTradeRefundAmountHist.setUseTradeId(repAccMqDetailModel.getFlowId());
                  accTradeRefundAmountHist.setUseAmount(canRefund);
                  accTradeRefundAmountHist.setTradeType(repAccMqDetailModel.getFlowType());
                  this.accTradeUseAmountHistService.insertUseAmountHist(accTradeRefundAmountHist);
                  refundAmount = NumberUtil.sub(refundAmount, canRefund);
                  if (refundAmount.compareTo(BigDecimal.ZERO) <= 0) {
                     break;
                  }
               }
            }
         }
      }
   }

   protected void calculateSubsidyAmount(Long custId, RepAccMqDetailModel repAccMqDetailModel) {
      BigDecimal calculateAmount = repAccMqDetailModel.getAmount();

      do {
         AccTradeWalletDetail expirationWalletDetail = this.accTradeWalletDetailService.selectOneSubsidyExpirationTrade(custId);
         if (ObjectUtil.isNull(expirationWalletDetail)) {
            throw new ServiceException("不存在可使用的补贴过期记录");
         }

         BigDecimal canUserAmount = expirationWalletDetail.getAmount().subtract(expirationWalletDetail.getUseAmount()).max(BigDecimal.ZERO);
         BigDecimal min = calculateAmount.min(canUserAmount);
         this.accTradeWalletDetailService.updateExpiredClearTradeUseAmount(expirationWalletDetail.getId(), min);
         AccTradeUseAmountHist accTradeUseAmountHist = new AccTradeUseAmountHist();
         accTradeUseAmountHist.setOriginTradeId(expirationWalletDetail.getId());
         accTradeUseAmountHist.setUseTradeId(repAccMqDetailModel.getFlowId());
         accTradeUseAmountHist.setUseAmount(min);
         accTradeUseAmountHist.setTradeType(repAccMqDetailModel.getFlowType());
         this.accTradeUseAmountHistService.insertUseAmountHist(accTradeUseAmountHist);
         calculateAmount = NumberUtil.sub(calculateAmount, min);
      } while(calculateAmount.compareTo(BigDecimal.ZERO) > 0);

   }
}
