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

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSONObject;
import com.bonus.canteen.core.marketing.v2.model.MarketRuleRecord;
import com.bonus.canteen.core.marketing.v2.rule.price.dto.RulePriceLimitDTO;
import com.bonus.canteen.core.marketing.v2.rule.price.dto.RulePriceResultOrderDTO;
import com.bonus.canteen.core.marketing.v2.rule.price.handler.deductionfull.constants.DiscountTypeEnum;
import com.bonus.canteen.core.marketing.v2.rule.price.handler.deductionfull.constants.PriceTypeEnum;
import com.bonus.canteen.core.marketing.v2.rule.price.handler.deductionfull.dto.PriceDeductionFullDTO;
import com.bonus.canteen.core.marketing.v2.rule.price.handler.deductionfull.dto.PriceDeductionFullItemDTO;
import com.bonus.canteen.core.marketing.v2.rule.price.handler.deductionfull.extension.PriceDeductionFullHandlerExtension;
import com.bonus.canteen.core.marketing.v2.service.MarketRuleRecordService;
import com.bonus.canteen.core.marketing.vo.MarketRuleVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class DefaultPriceDeDuctionFullHandlerImpl implements PriceDeductionFullHandlerExtension {
   private static final Logger log = LoggerFactory.getLogger(DefaultPriceDeDuctionFullHandlerImpl.class);
   @Autowired
   private MarketRuleRecordService recordService;

   public void handle(RulePriceResultOrderDTO order, MarketRuleVO rule, List<RulePriceResultOrderDTO> orderResults) {
      PriceDeductionFullDTO deductionDTO = (PriceDeductionFullDTO)JSONObject.parseObject(rule.getRuleInfo(), PriceDeductionFullDTO.class);
      if (!CollUtil.isEmpty(deductionDTO.getItems())) {
         if (Objects.nonNull(deductionDTO.getMaxCount())) {
            RulePriceLimitDTO limitDTO = new RulePriceLimitDTO(order, deductionDTO.getLimitType(), (List)null);
            List<MarketRuleRecord> records = this.recordService.getRuleRecordByRule(order.getCustId(), limitDTO.getBeginDate(), limitDTO.getEndDate(), limitDTO.getMealtimeTypeList(), CollUtil.newArrayList(new Long[]{rule.getRuleId()}));
            long count = records.stream().filter((e) -> {
               return e.getDiscountsAmount().compareTo(BigDecimal.ZERO) != 0;
            }).count();
            log.info("【计价规则】已经使用优惠次数：{}", Math.toIntExact(count));
            log.info("【计价规则】最大优惠次数：{}", deductionDTO.getMaxCount());
            if (deductionDTO.getMaxCount().compareTo(Math.toIntExact(count)) <= 0) {
               return;
            }
         }

         Integer priceType = deductionDTO.getPriceType();
         if (Objects.equals(PriceTypeEnum.PRICE_TYPE_STEP.getKey(), priceType)) {
            this.step(order, deductionDTO);
         } else {
            this.cycle(order, deductionDTO);
         }

      }
   }

   protected void step(RulePriceResultOrderDTO order, PriceDeductionFullDTO deductionDTO) {
      Integer discountType = deductionDTO.getDiscountType();
      BigDecimal payableAmount = order.getPayableAmount();
      List<PriceDeductionFullItemDTO> items = (List)deductionDTO.getItems().stream().sorted(Comparator.comparing(PriceDeductionFullItemDTO::getDoorAmount).reversed()).collect(Collectors.toList());
      items.stream().filter((e) -> {
         return payableAmount.compareTo(e.getDoorAmount()) >= 0;
      }).findFirst().ifPresent((firstStep) -> {
         BigDecimal discount = firstStep.getDiscount();
         BigDecimal realAmount = Objects.equals(DiscountTypeEnum.DISCOUNT_TYPE_REDUCTION.getKey(), discountType) ? (payableAmount.compareTo(discount) <= 0 ? BigDecimal.ZERO : payableAmount.subtract(discount)) : payableAmount.multiply(discount).setScale(0, RoundingMode.DOWN);
         order.setRealAmount(realAmount);
         order.setDiscountsAmount(payableAmount.subtract(realAmount));
      });
   }

   protected void cycle(RulePriceResultOrderDTO order, PriceDeductionFullDTO deductionDTO) {
      Integer discountType = deductionDTO.getDiscountType();
      BigDecimal payableAmount = order.getPayableAmount();
      PriceDeductionFullItemDTO item = (PriceDeductionFullItemDTO)deductionDTO.getItems().get(0);
      BigDecimal doorAmount = item.getDoorAmount();
      BigDecimal discount = item.getDiscount();
      BigDecimal times = payableAmount.divide(doorAmount, 0, RoundingMode.DOWN);
      BigDecimal realAmount;
      BigDecimal discountsAmount;
      if (Objects.equals(DiscountTypeEnum.DISCOUNT_TYPE_REDUCTION.getKey(), discountType)) {
         BigDecimal cacAmount = discount.multiply(times);
         realAmount = payableAmount.compareTo(cacAmount) > 0 ? payableAmount.subtract(cacAmount) : BigDecimal.ZERO;
         discountsAmount = payableAmount.subtract(realAmount);
      } else {
         realAmount = doorAmount.multiply(times).multiply(discount).setScale(0, RoundingMode.DOWN).add(payableAmount.subtract(doorAmount.multiply(times)));
         discountsAmount = payableAmount.subtract(realAmount);
      }

      order.setRealAmount(realAmount);
      order.setDiscountsAmount(discountsAmount);
   }
}
