package com.bonus.core.marketing.v2.rule.recharge.handler.managecost.extension.impl;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSONObject;
import com.bonus.core.account.v3.metadata.enums.AccWalletIdEnum;
import com.bonus.core.marketing.util.EnumUtil;
import com.bonus.core.marketing.v2.rule.recharge.constants.RuleRechargeComputeTypeEnum;
import com.bonus.core.marketing.v2.rule.recharge.constants.RuleRechargeTypeEnum;
import com.bonus.core.marketing.v2.rule.recharge.dto.RuleRechargeResultDTO;
import com.bonus.core.marketing.v2.rule.recharge.handler.managecost.dto.RechargeCostDTO;
import com.bonus.core.marketing.v2.rule.recharge.handler.managecost.dto.RechargeCostItemDTO;
import com.bonus.core.marketing.v2.rule.recharge.handler.managecost.extension.RechargeCostHandlerExtension;
import com.bonus.core.marketing.vo.MarketRuleVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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 DefaultRechargeCostHandlerImpl implements RechargeCostHandlerExtension {
   private static final Logger log = LoggerFactory.getLogger(DefaultRechargeCostHandlerImpl.class);

   @Override
   public void handle(RuleRechargeResultDTO resultDTO, MarketRuleVO ruleInfo) {
      RechargeCostDTO rule = (RechargeCostDTO)JSONObject.parseObject(ruleInfo.getRuleInfo(), RechargeCostDTO.class);
      if (!CollUtil.isEmpty(rule.getItems())) {
         Integer rechargeType = rule.getRechargeType();
         RuleRechargeTypeEnum typeEnum = (RuleRechargeTypeEnum) EnumUtil.getEnumByKey(RuleRechargeTypeEnum.class, rechargeType);
         if (!Objects.isNull(typeEnum)) {
            switch (typeEnum) {
               case RECHARGE_TYPE_STEP:
                  this.step(resultDTO, rule.getItems());
                  break;
               case RECHARGE_TYPE_CYCLE:
                  this.cycle(resultDTO, rule.getItems());
                  break;
               default:
                  this.fixed(resultDTO, rule.getItems());
            }

            resultDTO.getWalletDetails().stream().filter((e) -> {
               return Objects.equals(e.getWalletId(), AccWalletIdEnum.WALLET.getKey());
            }).findFirst().ifPresent((e) -> {
               e.setAmount(e.getAmount().subtract(resultDTO.getManageCost()));
            });
         }
      }
   }

   protected void fixed(RuleRechargeResultDTO resultDTO, List<RechargeCostItemDTO> items) {
      RechargeCostItemDTO itemDTO = (RechargeCostItemDTO)items.get(0);
      BigDecimal doorAmount = itemDTO.getDoorAmount();
      if (resultDTO.getAmount().compareTo(doorAmount) >= 0) {
         BigDecimal manageCost = this.getManageCost(resultDTO, itemDTO);
         resultDTO.setManageCost(manageCost);
         resultDTO.setActualAmount(resultDTO.getActualAmount().subtract(manageCost));
      }
   }

   protected void step(RuleRechargeResultDTO resultDTO, List<RechargeCostItemDTO> items) {
      BigDecimal amount = resultDTO.getAmount();
      List<RechargeCostItemDTO> sortItems = (List)items.stream().sorted(Comparator.comparing(RechargeCostItemDTO::getDoorAmount).reversed()).collect(Collectors.toList());
      sortItems.stream().filter((e) -> {
         return amount.compareTo(e.getDoorAmount()) >= 0;
      }).findFirst().ifPresent((firstStep) -> {
         BigDecimal manageCost = this.getManageCost(resultDTO, firstStep);
         resultDTO.setManageCost(manageCost);
         resultDTO.setActualAmount(resultDTO.getActualAmount().subtract(manageCost));
      });
   }

   protected void cycle(RuleRechargeResultDTO resultDTO, List<RechargeCostItemDTO> items) {
      RechargeCostItemDTO item = (RechargeCostItemDTO)items.get(0);
      Integer computeType = item.getComputeType();
      BigDecimal amount = resultDTO.getAmount();
      BigDecimal doorAmount = item.getDoorAmount();
      BigDecimal discount = item.getDiscount();
      BigDecimal times = amount.divide(doorAmount, 0, RoundingMode.DOWN);
      BigDecimal manageCost = Objects.equals(RuleRechargeComputeTypeEnum.COMPUTE_TYPE_AMOUNT.getKey(), computeType) ? discount.multiply(times) : doorAmount.multiply(times).multiply(discount).setScale(0, RoundingMode.DOWN);
      resultDTO.setManageCost(manageCost);
      resultDTO.setActualAmount(resultDTO.getActualAmount().subtract(manageCost));
   }

   protected BigDecimal getManageCost(RuleRechargeResultDTO resultDTO, RechargeCostItemDTO item) {
      Integer computeType = item.getComputeType();
      BigDecimal discount = item.getDiscount();
      return RuleRechargeComputeTypeEnum.COMPUTE_TYPE_AMOUNT.getKey().equals(computeType) ? discount : resultDTO.getAmount().multiply(discount).setScale(0, RoundingMode.DOWN);
   }
}
