package com.bonus.canteen.core.marketing.v2.rule.price.api;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import com.bonus.common.houqin.constant.LeConstants;
import com.bonus.canteen.core.common.utils.JacksonUtil;
import com.bonus.canteen.core.customer.api.CustInfoApi;
import com.bonus.canteen.core.customer.constants.CustConstant;
import com.bonus.canteen.core.customer.model.CustInfo;
import com.bonus.canteen.core.marketing.util.EnumUtil;
import com.bonus.canteen.core.marketing.v2.custom.MarketRuleCustomBusiness;
import com.bonus.canteen.core.marketing.v2.model.MarketRuleRecord;
import com.bonus.canteen.core.marketing.v2.model.MarketRuleRecordWallet;
import com.bonus.canteen.core.marketing.v2.rule.param.RuleRangeParam;
import com.bonus.canteen.core.marketing.v2.rule.price.constants.RulePriceEnum;
import com.bonus.canteen.core.marketing.v2.rule.price.dto.*;
import com.bonus.canteen.core.marketing.v2.rule.price.handler.RulePriceHandler;
import com.bonus.canteen.core.marketing.v2.rule.price.handler.RulePriceProvider;
import com.bonus.canteen.core.marketing.v2.service.MarketRuleRecordService;
import com.bonus.canteen.core.marketing.v2.service.MarketRuleRecordWalletService;
import com.bonus.canteen.core.marketing.v2.service.MarketRuleService;
import com.bonus.canteen.core.marketing.vo.MarketRuleRecordVO;
import com.bonus.canteen.core.marketing.vo.MarketRuleVO;
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.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class RulePriceApi {
   private static final Logger log = LoggerFactory.getLogger(RulePriceApi.class);
   @Autowired
   private RulePriceProvider rulePriceProvider;
   @Autowired
   private MarketRuleService marketRuleService;
   @Autowired
   private CustInfoApi custInfoApi;
   @Autowired
   private MarketRuleRecordService recordService;
   @Autowired
   private MarketRuleRecordWalletService recordWalletService;
   @Autowired
   private MarketRuleCustomBusiness marketRuleCustomBusiness;

   public RulePriceResultDTO compute(RulePriceDTO rulePriceDTO) {
      log.info("【计价规则】开始");
      List<RulePriceOrderDTO> orders = rulePriceDTO.getOrders();
      List<Long> orderIds = (List)orders.stream().map(RulePriceOrderDTO::getOrderId).collect(Collectors.toList());
      CustInfo custInfo = this.custInfoApi.getCustInfoByCustId(Objects.isNull(rulePriceDTO.getCustId())
              ? CustConstant.TEMPORARY_CUST_ID : rulePriceDTO.getCustId());
      List<RulePriceResultOrderDTO> orderResults = RulePriceResultOrderDTO.convertToResultOrder(orders);

      try {
         orderResults.forEach((order) -> {
            RuleRangeParam ruleRangeParam = RuleRangeParam.rulePriceRangeParam(order, custInfo);
            log.info("【计价规则】查找合适规则入参：{}", JSONUtil.toJsonStr(ruleRangeParam));
            List<MarketRuleVO> suitableRules = this.marketRuleService.getSuitableRules(ruleRangeParam);
            if (CollUtil.isEmpty(suitableRules)) {
               log.info("【计价规则】订单：{}，未匹配到对应规则", order.getOrderId());
            } else {
               suitableRules = this.marketRuleCustomBusiness.beforeCompute(order, suitableRules);
               List<MarketRuleRecord> records = new ArrayList();
               List<MarketRuleRecordWallet> recordWallets = new ArrayList();
               if (Objects.equals(order.getIfOnline(), LeConstants.COMMON_YES)) {
                  suitableRules.stream().filter((e) -> {
                     return RulePriceEnum.isLimitTimesRule(e.getRuleType());
                  }).forEach((e) -> {
                     this.handle(order, e, orderResults, records, recordWallets);
                  });
               }

               suitableRules.stream().filter((e) -> {
                  return RulePriceEnum.isDiscountRule(e.getRuleType());
               }).findFirst().ifPresent((e) -> {
                  this.handle(order, e, orderResults, records, recordWallets);
               });
               if (Objects.equals(order.getIfOnline(), LeConstants.COMMON_YES)) {
                  suitableRules.stream().filter((e) -> {
                     return RulePriceEnum.isLimitAmountRule(e.getRuleType());
                  }).forEach((e) -> {
                     this.handle(order, e, orderResults, records, recordWallets);
                  });
               }

               if (Objects.equals(rulePriceDTO.getTryFlag(), LeConstants.COMMON_NO)) {
                  suitableRules.stream().filter((e) -> {
                     return RulePriceEnum.isGiveRule(e.getRuleType());
                  }).findFirst().ifPresent((e) -> {
                     this.handle(order, e, orderResults, records, recordWallets);
                  });
               }

               this.recordService.saveBatch(records);
               this.recordWalletService.saveBatch(recordWallets);
               log.info("【计价规则】该订单规则计算结果入库成功");
            }
         });
      } catch (Exception var7) {
         this.recordService.disableRecord(orderIds);
         throw var7;
      }

      RulePriceResultDTO result = new RulePriceResultDTO(orderResults);
      log.info("【计价规则】规则最终计算结果：{}", JacksonUtil.writeValueAsString(result));
      if (Objects.equals(rulePriceDTO.getTryFlag(), LeConstants.COMMON_YES)) {
         this.recordService.disableRecord(orderIds);
      }

      return result;
   }

   protected void handle(RulePriceResultOrderDTO order, MarketRuleVO ruleInfo, List<RulePriceResultOrderDTO> orderResults, List<MarketRuleRecord> records, List<MarketRuleRecordWallet> recordWallets) {
      RulePriceHandler handler = this.rulePriceProvider.getMarketPriceHandler(ruleInfo.getRuleType());
      if (Objects.isNull(handler)) {
         log.info("【计价规则】规则类型：{}，未找到对应规则类型的实现方法", ruleInfo.getRuleType());
      } else {
         log.info("【计价规则】规则类型：{}，规则详情：{}", EnumUtil.getEnumByKey(RulePriceEnum.class, ruleInfo.getRuleType()).getValue(), JSONUtil.toJsonStr(ruleInfo));
         handler.handle(order, ruleInfo, orderResults);
         this.formatRecord(order, ruleInfo, records, recordWallets);
      }
   }

   protected void formatRecord(RulePriceResultOrderDTO order, MarketRuleVO ruleInfo, List<MarketRuleRecord> records
           , List<MarketRuleRecordWallet> recordWallets) {
      Long recordId = Id.next();
      MarketRuleRecordVO recordVO = new MarketRuleRecordVO(order, ruleInfo, recordId);
      order.getRuleRecord().add(recordVO);
      records.add(recordVO);
      List<RulePriceWalletDTO> walletDetails = order.getWalletDetails();
      List<MarketRuleRecordWallet> tempRecordWallets = BeanUtil.copyToList(walletDetails, MarketRuleRecordWallet.class);
      tempRecordWallets.forEach((e) -> {
         e.setRecordId(recordId);
      });
      recordWallets.addAll(tempRecordWallets);
      log.info("【计价规则】该订单规则计算结果：{}", JSONUtil.toJsonStr(order));
   }
}
