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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
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.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.recharge.constants.RuleRechargeEnum;
import com.bonus.canteen.core.marketing.v2.rule.recharge.dto.RuleRechargeComputeDTO;
import com.bonus.canteen.core.marketing.v2.rule.recharge.dto.RuleRechargeResultDTO;
import com.bonus.canteen.core.marketing.v2.rule.recharge.dto.RuleRechargeWalletDTO;
import com.bonus.canteen.core.marketing.v2.rule.recharge.handler.RuleRechargeHandler;
import com.bonus.canteen.core.marketing.v2.rule.recharge.handler.RuleRechargeProvider;
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.MarketRuleVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Service
public class RuleRechargeApi {
   private static final Logger log = LoggerFactory.getLogger(RuleRechargeApi.class);
   @Resource
   private RuleRechargeProvider ruleRechargeProvider;
   @Resource
   private MarketRuleService marketRuleService;
   @Resource
   private CustInfoApi custInfoApi;
   @Resource
   private MarketRuleRecordService recordService;
   @Resource
   private MarketRuleRecordWalletService recordWalletService;

   public RuleRechargeResultDTO compute(RuleRechargeComputeDTO computeDTO) {
      log.info("【充值规则】开始");
      RuleRechargeResultDTO resultDTO = new RuleRechargeResultDTO(computeDTO);
      Long custId = computeDTO.getCustId();
      CustInfo custInfo = this.custInfoApi.getCustInfoByCustId(Objects.isNull(custId) ? CustConstant.TEMPORARY_CUST_ID : custId);
      RuleRangeParam ruleRangeParam = RuleRangeParam.ruleRechargeRangeParam(computeDTO, custInfo);
      log.info("【充值规则】查找合适规则入参：{}", JSONUtil.toJsonStr(ruleRangeParam));
      List<MarketRuleVO> suitableRules = this.marketRuleService.getSuitableRules(ruleRangeParam);
      if (CollUtil.isEmpty(suitableRules)) {
         log.info("【充值规则】未匹配到对应规则");
         return resultDTO;
      } else {
         List<MarketRuleRecord> records = new ArrayList();
         List<MarketRuleRecordWallet> recordWallets = new ArrayList();
         suitableRules.stream().filter((e) -> {
            return RuleRechargeEnum.isLimitAmountRule(e.getRuleType());
         }).forEach((e) -> {
            this.handle(resultDTO, e, records, recordWallets);
         });
         suitableRules.stream().filter((e) -> {
            return RuleRechargeEnum.isDiscountRule(e.getRuleType());
         }).findFirst().ifPresent((e) -> {
            this.handle(resultDTO, e, records, recordWallets);
         });
         suitableRules.stream().filter((e) -> {
            return RuleRechargeEnum.isOtherFeeRule(e.getRuleType());
         }).findFirst().ifPresent((e) -> {
            this.handle(resultDTO, e, records, recordWallets);
         });
         this.recordService.saveBatch(records);
         this.recordWalletService.saveBatch(recordWallets);
         log.info("【充值规则】规则计算结果入库成功");
         log.info("【充值规则】规则最终计算结果：{}", JSONUtil.toJsonStr(resultDTO));
         return resultDTO;
      }
   }

   protected void handle(RuleRechargeResultDTO resultDTO, MarketRuleVO rule, List<MarketRuleRecord> records, List<MarketRuleRecordWallet> recordWallets) {
      RuleRechargeHandler handler = this.ruleRechargeProvider.getMarketRechargeHandler(rule.getRuleType());
      if (Objects.isNull(handler)) {
         log.info("【充值规则】规则类型：{}，未找到对应规则类型的实现方法", rule.getRuleType());
      } else {
         log.info("【充值规则】规则类型：{}，规则详情：{}", ((RuleRechargeEnum) EnumUtil.getEnumByKey(RuleRechargeEnum.class, rule.getRuleType())).getValue(), JSONUtil.toJsonStr(rule));
         handler.handle(resultDTO, rule);
         log.info("【充值规则】规则计算结果：{}", JSONUtil.toJsonStr(resultDTO));
         this.formatRecord(resultDTO, rule, records, recordWallets);
      }
   }

   protected void formatRecord(RuleRechargeResultDTO resultDTO, MarketRuleVO rule, List<MarketRuleRecord> records, List<MarketRuleRecordWallet> recordWallets) {
      log.info("【充值规则】规则计算结果组装开始");
      MarketRuleRecord record = new MarketRuleRecord(resultDTO, rule);
      resultDTO.getRuleRecord().add(record);
      records.add(record);
      List<RuleRechargeWalletDTO> walletDetails = resultDTO.getWalletDetails();
      List<MarketRuleRecordWallet> tempRecordWallets = BeanUtil.copyToList(walletDetails, MarketRuleRecordWallet.class);
      tempRecordWallets.forEach((e) -> {
         e.setRecordId(record.getRecordId());
      });
      recordWallets.addAll(tempRecordWallets);
      log.info("【充值规则】规则计算结果组装成功");
   }
}
