package com.bonus.canteen.core.account.v3.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.bonus.canteen.core.account.v3.constants.AccTradeStateEnum;
import com.bonus.canteen.core.account.v3.constants.AccUpdateWalletOperateEnum;
import com.bonus.canteen.core.account.v3.metadata.enums.AccWalletIdEnum;
import com.bonus.canteen.core.account.v3.model.AccTrade;
import com.bonus.canteen.core.account.v3.mq.send.dto.RepAccMqDTO;
import com.bonus.canteen.core.account.v3.po.*;
import com.bonus.canteen.core.account.v3.service.AccBusinessService;
import com.bonus.canteen.core.account.v3.service.AccTradeService;
import com.bonus.canteen.core.account.v3.service.AccTradeWalletDetailService;
import com.bonus.canteen.core.account.v3.service.AccWalletInfoService;
import com.bonus.canteen.core.account.v3.utils.AccUtils;
import com.bonus.canteen.core.account.v3.web.dto.AccRechargeBackDTO;
import com.bonus.canteen.core.account.v3.web.vo.AccConsumeWalletVO;
import com.bonus.canteen.core.account.v3.web.vo.AccUpdateWalletBalanceVO;
import com.bonus.canteen.core.common.utils.TenantContextHolder;
import com.bonus.canteen.core.marketing.v2.api.MarketApi;
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.pay.common.constants.PayChannelEnum;
import com.bonus.canteen.core.pay.common.constants.PayStateEnum;
import com.bonus.canteen.core.pay.common.constants.PayTypeEnum;
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.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class AccBusinessServiceImpl implements AccBusinessService {
   private static final Logger log = LoggerFactory.getLogger(AccBusinessServiceImpl.class);
   @Resource
   @Lazy
   private AccWalletInfoService accWalletInfoService;
   @Resource
   @Lazy
   private AccTradeService accTradeService;
   @Resource
   @Lazy
   private AccTradeWalletDetailService accTradeWalletDetailService;
   @Resource
   @Lazy
   private MarketApi marketApi;


   @Override
   public AccConsumeWalletVO doConsumeUpdateWalletAndAddTradeV2(AccConsumeUpdateWalletPO updateWalletPo) {
      log.info("[账户消费]->修改钱包,新增记录:{}", JSONUtil.toJsonStr(updateWalletPo));
      if (CollUtil.isEmpty(updateWalletPo.getWalletPayList())) {
         return this.doConsumeAddTradeForPayZero(updateWalletPo);
      } else {
         long tradeId = Id.next();
         LocalDateTime tradeTime = LocalDateTime.now();
         Iterator var5 = updateWalletPo.getWalletPayList().iterator();

         while(var5.hasNext()) {
            AccWalletPayPO walletPayPo = (AccWalletPayPO)var5.next();
            if (ObjectUtil.isNotNull(walletPayPo.getAmount()) && walletPayPo.getAmount().compareTo(BigDecimal.ZERO) > 0) {
               Integer walletId = walletPayPo.getWalletId();
               AccWalletBalanceUpdatePO rechargePo = (new AccWalletBalanceUpdatePO()).setOperationType(AccUpdateWalletOperateEnum.DECREASE_BAL).setCustId(updateWalletPo.getCustId()).setWalletId(walletId).setAmount(walletPayPo.getAmount());
               AccUpdateWalletBalanceVO accUpdateWalletBalanceVO = this.accWalletInfoService.updateAccWalletBalance(rechargePo);
               AccTradeWalletPO accTradeWalletPo = AccTradeWalletPO.builder().tradeId(tradeId).custId(updateWalletPo.getCustId()).walletId(walletId).tradeType(updateWalletPo.getTradeType()).amount(walletPayPo.getAmount()).walletBal(AccUtils.getWalletBal(accUpdateWalletBalanceVO.getWalletInfoList(), walletId)).frozenBalance(AccUtils.getWalletFrozenBal(accUpdateWalletBalanceVO.getWalletInfoList(), walletId)).tradeTime(tradeTime).build();
               this.accTradeWalletDetailService.insertAccTradeWalletDetail(accTradeWalletPo);
            }
         }

         AccUpdateWalletBalanceVO accWalletBalance = this.accWalletInfoService.getAccWalletBalanceByCustId(updateWalletPo.getCustId());
         AccTradeAddPO accTradeAddPo = AccTradeAddPO.builder().tradeId(tradeId).tradeTime(tradeTime).custId(updateWalletPo.getCustId()).psnType(updateWalletPo.getPsnType()).orgId(updateWalletPo.getOrgId()).actualAmount(updateWalletPo.getAmount()).amount(updateWalletPo.getAmount()).walletBalTotal(accWalletBalance.getAccBalTotal()).accAllBal(accWalletBalance.getAccAllBal()).payChannel(PayChannelEnum.ACC.getKey()).payType(PayTypeEnum.MEAL_CARD.getKey()).payState(updateWalletPo.getPayState()).tradeType(updateWalletPo.getTradeType()).tradeState(AccTradeStateEnum.TAKE_EFFECT.getKey()).machineSn(updateWalletPo.getMachineSn()).canteenId(updateWalletPo.getCanteenId()).remark(updateWalletPo.getRemark()).leOrdNo(updateWalletPo.getOrderTradeId()).crby(updateWalletPo.getUserName()).build();
         this.accTradeService.insertAccTradeForTradeId(accTradeAddPo);
         log.info("账户消费->修改钱包,新增记录结束");
         return (new AccConsumeWalletVO()).setAccTradeId(tradeId).setAccAllBal(accWalletBalance.getAccAllBal()).setAccBalTotal(accWalletBalance.getAccBalTotal()).setWalletInfoList(accWalletBalance.getWalletInfoList());
      }
   }

   public AccConsumeWalletVO doConsumeAddTradeForPayZero(AccConsumeUpdateWalletPO updateWalletPo) {
      log.info("[账户消费]0元消费,新增记录:{}", JSONUtil.toJsonStr(updateWalletPo));
      Integer walletId = (Integer)updateWalletPo.getPayWalletIdList().stream().findFirst().orElse(AccWalletIdEnum.WALLET.getKey());
      long tradeId = Id.next();
      LocalDateTime tradeTime = LocalDateTime.now();
      AccUpdateWalletBalanceVO accWalletBalance = this.accWalletInfoService.getAccWalletBalanceByCustId(updateWalletPo.getCustId());
      AccTradeAddPO accTradeAddPo = AccTradeAddPO.builder().tradeId(tradeId).tradeTime(tradeTime).custId(updateWalletPo.getCustId()).psnType(updateWalletPo.getPsnType()).orgId(updateWalletPo.getOrgId()).actualAmount(BigDecimal.ZERO).amount(BigDecimal.ZERO).walletBalTotal(accWalletBalance.getAccBalTotal()).accAllBal(accWalletBalance.getAccAllBal()).payChannel(PayChannelEnum.ACC.getKey()).payType(PayTypeEnum.MEAL_CARD.getKey()).payState(updateWalletPo.getPayState()).tradeType(updateWalletPo.getTradeType()).tradeState(AccTradeStateEnum.TAKE_EFFECT.getKey()).machineSn(updateWalletPo.getMachineSn()).canteenId(updateWalletPo.getCanteenId()).remark(updateWalletPo.getRemark()).leOrdNo(updateWalletPo.getOrderTradeId()).crby(updateWalletPo.getUserName()).build();
      this.accTradeService.insertAccTradeForTradeId(accTradeAddPo);
      AccTradeWalletPO accTradeWalletPo = AccTradeWalletPO.builder().tradeId(tradeId).custId(updateWalletPo.getCustId()).walletId(walletId).tradeType(updateWalletPo.getTradeType()).amount(BigDecimal.ZERO).walletBal(AccUtils.getWalletBal(accWalletBalance.getWalletInfoList(), walletId)).frozenBalance(AccUtils.getWalletFrozenBal(accWalletBalance.getWalletInfoList(), walletId)).tradeTime(tradeTime).build();
      this.accTradeWalletDetailService.insertAccTradeWalletDetail(accTradeWalletPo);
      log.info("[账户消费]0元消费,新增记录结束");
      return (new AccConsumeWalletVO()).setAccTradeId(tradeId).setAccAllBal(accWalletBalance.getAccAllBal()).setAccBalTotal(accWalletBalance.getAccBalTotal()).setWalletInfoList(accWalletBalance.getWalletInfoList());
   }

   @Override
   @Transactional(
           rollbackFor = {Exception.class},
           propagation = Propagation.REQUIRES_NEW
   )
   public void accRechargeModifyAndUpdate(AccRechargeBackDTO accRechargeBackDTO) {
      log.info("[账户]支付结果->开始处理入参:{}", JSONUtil.toJsonStr(accRechargeBackDTO));
      AccTrade accTrade = (AccTrade)this.accTradeService.getById(accRechargeBackDTO.getAccTradeId());
      if (ObjectUtil.isNull(accTrade)) {
         log.error("[账户]支付结果->交易记录不存在");
      } else if (PayStateEnum.isPaidState(accTrade.getPayState())) {
         log.error("[账户]支付结果->记录已经被处理:{}", JSONUtil.toJsonStr(accTrade));
      } else {
         AccTrade updateTrade = new AccTrade();
         updateTrade.setId(accTrade.getId());
         updateTrade.setPayState(accRechargeBackDTO.getPayState());
         if (PayStateEnum.isPaidState(accRechargeBackDTO.getPayState())) {
            RuleRechargeComputeDTO ruleRechargeComputeDTO = this.packageRuleRechargeComputeDTO(accTrade);
            log.info("[账户]支付结果->支付成功,调用充值计算规则入参:{}", JSONUtil.toJsonStr(ruleRechargeComputeDTO));
            RuleRechargeResultDTO ruleRechargeResultDTO = this.marketApi.ruleRechargeCompute(ruleRechargeComputeDTO);
            log.info("[账户]支付结果->支付成功,调用充值计算规则结果={}", JSONUtil.toJsonStr(ruleRechargeResultDTO));
            LocalDateTime now = LocalDateTime.now();
            this.addAccTradeWalletDeatil(accTrade.getId(), accTrade.getCustId(), ruleRechargeResultDTO.getWalletDetails(), now);
            AccUpdateWalletBalanceVO accWalletBalance = this.accWalletInfoService.getAccWalletBalanceByCustId(accTrade.getCustId());
            updateTrade.setTradeTime(now);
            updateTrade.setTradeState(AccTradeStateEnum.TAKE_EFFECT.getKey());
            updateTrade.setActualAmount(ruleRechargeResultDTO.getActualAmount());
            updateTrade.setManageCost(ruleRechargeResultDTO.getManageCost());
            updateTrade.setWalletBalTotal(accWalletBalance.getAccBalTotal());
            updateTrade.setAccAllBal(accWalletBalance.getAccAllBal());
            updateTrade.setLeOrdNo(accRechargeBackDTO.getPayTradeId());
            updateTrade.setThirdTradeNo(accRechargeBackDTO.getThirdTradeNo());
            updateTrade.setRemark(accRechargeBackDTO.getTradeResult());
            log.info("[账户]支付结果->支付成功,更新充值记录对象开始,{}", JSONUtil.toJsonStr(updateTrade));
            this.accTradeService.updateTradeById(updateTrade);
            log.info("[账户]支付结果->支付成功,更新充值记录结束");
            this.sendAccSendMq(Collections.singletonList(accTrade.getId()));
         } else {
            Integer tradeSate = AccTradeStateEnum.CREATE.getKey();
            if (PayStateEnum.isFailedState(accRechargeBackDTO.getPayState())) {
               updateTrade.setFailReason(accRechargeBackDTO.getTradeResult());
               tradeSate = AccTradeStateEnum.CLOSE.getKey();
            }

            updateTrade.setTradeState(tradeSate);
            log.info("[账户]支付结果->未成功,更新充值记录对象开始,{}", JSONUtil.toJsonStr(updateTrade));
            this.accTradeService.updateTradeById(updateTrade);
         }

      }
   }

   protected RuleRechargeComputeDTO packageRuleRechargeComputeDTO(AccTrade accTrade) {
      return (new RuleRechargeComputeDTO()).setCustId(accTrade.getCustId()).setAmount(accTrade.getAmount()).setPayChannel(accTrade.getPayChannel()).setPayType(accTrade.getPayType()).setTradeId(accTrade.getId()).setTradeDate(LocalDate.now());
   }

   protected void addAccTradeWalletDeatil(Long tradeId, Long custId, List<RuleRechargeWalletDTO> walletDetails, LocalDateTime tradeTime) {
      log.info("[账户]支付结果->新增账户交易详情开始,{}", JSONUtil.toJsonStr(walletDetails));
      Iterator var5 = walletDetails.iterator();

      while(var5.hasNext()) {
         RuleRechargeWalletDTO walletDetail = (RuleRechargeWalletDTO)var5.next();
         AccWalletBalanceUpdatePO rechargePo = (new AccWalletBalanceUpdatePO()).setOperationType(AccUpdateWalletOperateEnum.AUGMENT_BAL).setCustId(custId).setWalletId(walletDetail.getWalletId()).setAmount(walletDetail.getAmount());
         AccUpdateWalletBalanceVO accUpdateWalletBalanceVO = this.updateAccWalletBalance(rechargePo);
         AccTradeWalletPO accTradeWalletPo = AccTradeWalletPO.builder().tradeId(tradeId).custId(custId).walletId(walletDetail.getWalletId()).tradeType(walletDetail.getTradeType()).amount(walletDetail.getAmount()).walletBal(AccUtils.getWalletBal(accUpdateWalletBalanceVO.getWalletInfoList(), walletDetail.getWalletId())).frozenBalance(AccUtils.getWalletFrozenBal(accUpdateWalletBalanceVO.getWalletInfoList(), walletDetail.getWalletId())).tradeTime(tradeTime).build();
         this.accTradeWalletDetailService.insertAccTradeWalletDetail(accTradeWalletPo);
      }

      log.info("[账户]支付结果->新增账户交易详情结束");
   }
   public AccUpdateWalletBalanceVO updateAccWalletBalance(AccWalletBalanceUpdatePO updatePo) {
      return this.accWalletInfoService.updateAccWalletBalance(updatePo);
   }

   public void sendAccSendMq(List<Long> tradeIdList) {
      if (CollUtil.isNotEmpty(tradeIdList)) {
         List<RepAccMqDTO> sendList = (List)tradeIdList.stream().map((item) -> {
            return RepAccMqDTO.builder().tradeId(item).build();
         }).collect(Collectors.toList());
//         this.accSendMq.accTradeSendHandle(TenantContextHolder.getTenantId(), sendList);
      }

   }
}
