package com.bonus.core.marketing.v2.rule.price.handler.deductionratio.extension.impl;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.bonus.common.core.exception.ServiceException;
import com.bonus.core.account.v3.api.AccPayBusinessApi;
import com.bonus.core.account.v3.constants.AccTradeTypeEnum;
import com.bonus.core.account.v3.metadata.enums.AccWalletIdEnum;
import com.bonus.core.marketing.v2.constants.MarketModuleTypeEnum;
import com.bonus.core.marketing.v2.model.MarketRule;
import com.bonus.core.marketing.v2.model.MarketRuleRecord;
import com.bonus.core.marketing.v2.model.MarketRuleRecordWallet;
import com.bonus.core.marketing.v2.rule.pay.api.RulePayApi;
import com.bonus.core.marketing.v2.rule.pay.dto.RulePayComputeDTO;
import com.bonus.core.marketing.v2.rule.pay.dto.RulePayResultDTO;
import com.bonus.core.marketing.v2.rule.price.dto.RulePriceResultOrderDTO;
import com.bonus.core.marketing.v2.rule.price.dto.RulePriceWalletDTO;
import com.bonus.core.marketing.v2.rule.price.handler.deductionratio.dto.PriceDeductionRatioDTO;
import com.bonus.core.marketing.v2.rule.price.handler.deductionratio.extension.PriceDeductionRatioHandlerExtension;
import com.bonus.core.marketing.v2.service.MarketRuleRecordService;
import com.bonus.core.marketing.v2.service.MarketRuleRecordWalletService;
import com.bonus.core.marketing.v2.service.MarketRuleService;
import com.bonus.core.marketing.vo.MarketRuleVO;
import com.bonus.core.order.common.constants.OrderTypeEnum;
import com.bonus.i18n.I18n;
import com.fasterxml.jackson.databind.JsonNode;
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 java.lang.invoke.SerializedLambda;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class DefaultDeductionRatioHandlerImpl implements PriceDeductionRatioHandlerExtension {
   private static final Logger log = LoggerFactory.getLogger(DefaultDeductionRatioHandlerImpl.class);
   @Autowired
   private MarketRuleRecordService recordService;
   @Autowired
   private MarketRuleRecordWalletService recordWalletService;
   @Autowired
   @Lazy
   private RulePayApi rulePayApi;
   @Autowired
   private AccPayBusinessApi accPayBusinessApi;
   @Autowired
   private MarketRuleService ruleService;

   public void handle(RulePriceResultOrderDTO order, MarketRuleVO rule, List<RulePriceResultOrderDTO> orderResults) {
      PriceDeductionRatioDTO deductionRatioDTO = (PriceDeductionRatioDTO)JSONObject.parseObject(rule.getRuleInfo(), PriceDeductionRatioDTO.class);
      if (!OrderTypeEnum.BUFFET.getKey().equals(order.getOrderType())) {
         RulePayResultDTO payResultDTO = this.rulePayApi.compute(new RulePayComputeDTO(order));
         List<Integer> walletIds = CollUtil.isEmpty(payResultDTO.getWalletIds()) ? this.accPayBusinessApi.getWalletPayDefaultOrder() : payResultDTO.getWalletIds();
         if (CollUtil.isEmpty(walletIds) || !CollUtil.containsAll(walletIds, CollUtil.newArrayList(new Integer[]{AccWalletIdEnum.WALLET.getKey(), AccWalletIdEnum.SUBSIDY.getKey()}))) {
            throw new ServiceException(I18n.getMessage("market_price_both_wallet", new Object[0]));
         }
      }

      BigDecimal amount = order.getPayableAmount();
      BigDecimal walletRatio = deductionRatioDTO.getWalletRatio();
      BigDecimal walletAmount = amount.multiply(walletRatio).setScale(0, RoundingMode.HALF_UP);
      BigDecimal subsidyAmount = amount.subtract(walletAmount);
      BigDecimal subsidyMaxAmount = deductionRatioDTO.getSubsidyMaxAmount();
      if (Objects.isNull(subsidyMaxAmount)) {
         this.formatWalletDetail(order, walletAmount, subsidyAmount);
      } else {
         BigDecimal remainSubsidyAmount = subsidyMaxAmount;
         List<MarketRule> rules = this.ruleService.listRuleByType(MarketModuleTypeEnum.RULE_PRICE.getKey(), rule.getRuleType());
         List<Long> ruleIds = (List)rules.stream().map(MarketRule::getRuleId).collect(Collectors.toList());
         List<MarketRuleRecord> records = this.recordService.getRuleRecordByRule(order.getCustId(), order.getOrderDate(), order.getOrderDate(), CollUtil.newArrayList(new Integer[]{order.getMealtimeType()}), ruleIds);
         if (CollUtil.isNotEmpty(records)) {
            List<Long> recordIds = (List)records.stream().map(MarketRuleRecord::getRecordId).collect(Collectors.toList());
            List<MarketRuleRecordWallet> recordWalletList = this.recordWalletService.list(Wrappers.lambdaQuery(MarketRuleRecordWallet.class).in(MarketRuleRecordWallet::getRecordId, recordIds).eq(MarketRuleRecordWallet::getWalletId, AccWalletIdEnum.SUBSIDY.getKey()));
            BigDecimal totalSubsidyAmount = (BigDecimal)recordWalletList.stream().map(MarketRuleRecordWallet::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            remainSubsidyAmount = subsidyMaxAmount.compareTo(totalSubsidyAmount) <= 0 ? BigDecimal.ZERO : subsidyMaxAmount.subtract(totalSubsidyAmount);
         }

         BigDecimal walletRealAmount = subsidyAmount.compareTo(remainSubsidyAmount) <= 0 ? walletAmount : amount.subtract(remainSubsidyAmount);
         BigDecimal subsidyRealAmount = subsidyAmount.compareTo(remainSubsidyAmount) <= 0 ? subsidyAmount : remainSubsidyAmount;
         this.formatWalletDetail(order, walletRealAmount, subsidyRealAmount);
      }
   }

   protected void formatWalletDetail(RulePriceResultOrderDTO order, BigDecimal walletAmount, BigDecimal subsidyAmount) {
      if (walletAmount.compareTo(BigDecimal.ZERO) > 0) {
         order.getWalletDetails().add(new RulePriceWalletDTO(AccWalletIdEnum.WALLET.getKey(), walletAmount, AccTradeTypeEnum.CONSUME.getKey(), (JsonNode)null));
      }

      if (subsidyAmount.compareTo(BigDecimal.ZERO) > 0) {
         order.getWalletDetails().add(new RulePriceWalletDTO(AccWalletIdEnum.SUBSIDY.getKey(), subsidyAmount, AccTradeTypeEnum.CONSUME.getKey(), (JsonNode)null));
      }

   }
}
