package com.bonus.core.pay.common.vo;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import com.bonus.constant.LeConstants;
import com.bonus.core.common.utils.JacksonUtil;
import com.bonus.core.order.common.constants.OrderAmountDetailTypeEnum;
import com.bonus.core.order.common.model.OrderAmountDetail;
import com.bonus.core.order.utils.LeNumUtil;
import com.bonus.core.pay.channel.account.vo.AccPayResultVO;
import com.bonus.core.pay.common.constants.PayChannelEnum;
import com.bonus.core.pay.common.constants.PayStateEnum;
import com.bonus.core.pay.common.constants.PayTypeEnum;
import com.bonus.core.pay.common.model.TradeChannel;
import com.bonus.utils.id.Id;
import com.fasterxml.jackson.databind.JsonNode;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;

public class TradeChannelVO {
   private Long tradeId;
   private Long tradeChannelId;
   private Integer tradeState;
   private String tradeResult;
   private Integer payType;
   private String payTypeName;
   private Integer payChannel;
   private String payChannelName;
   private BigDecimal amount;
   private BigDecimal refundAmount;
   private String outTradeNo;
   private LocalDateTime tradeTime;
   private JsonNode param;
   private AccPayResultVO accPayResultVO;

   public boolean ifLacksAccPayDetail() {
      if (!PayChannelEnum.ACC.getKey().equals(this.payChannel)) {
         return false;
      } else if (this.amount.compareTo(BigDecimal.ZERO) == 0) {
         return false;
      } else {
         return this.accPayResultVO == null || NumberUtil.add(new BigDecimal[]{this.accPayResultVO.getWalletPay(), this.accPayResultVO.getSubsidyPay(), this.accPayResultVO.getSubsidyPay()}).intValue() == 0;
      }
   }

   public boolean ifWechatScorePaying() {
      return PayTypeEnum.WECHAT_WITHHOLD.getKey().equals(this.payType) && PayStateEnum.isPayingState(this.tradeState);
   }

   public boolean ifAliAsyncFacePaying() {
      return (PayTypeEnum.ALI_FACE.getKey().equals(this.payType) || PayTypeEnum.ALI_ENTERPRISE_FACE.getKey().equals(this.payType)) && PayStateEnum.isPayingState(this.tradeState) && LeConstants.COMMON_YES.equals(JacksonUtil.getValueByPath((JsonNode)this.param, "alipayFaceAsync", LeConstants.COMMON_NO));
   }

   public BigDecimal calcRefundableAmount() {
      return NumberUtil.sub(this.amount, this.refundAmount);
   }

   public OrderAmountDetail convertToOrderAmountDetail(Long orderId, LocalDate orderDate, Long orderRefundId, BigDecimal amount, OrderAmountDetailTypeEnum amountDetailType) {
      OrderAmountDetail orderAmountDetail = new OrderAmountDetail();
      orderAmountDetail.setAmountDetailId(Id.next());
      orderAmountDetail.setTradeChannelId(this.tradeChannelId);
      orderAmountDetail.setOrderId(orderId);
      orderAmountDetail.setOrderDate(orderDate);
      orderAmountDetail.setOrderRefundId(orderRefundId);
      orderAmountDetail.setAmount(amount);
      orderAmountDetail.setPayType(this.payType);
      orderAmountDetail.setPayChannel(this.payChannel);
      orderAmountDetail.setAmountDetailType(amountDetailType.getKey());
      return orderAmountDetail;
   }

   public void shareAccPayResult(List<OrderAmountDetail> amountDetailList) {
      if (this.accPayResultVO != null && !CollUtil.isEmpty(amountDetailList)) {
         if (this.accPayResultVO.getWalletPay() != null) {
            LeNumUtil.calcShareAmount(amountDetailList, this.accPayResultVO.getWalletPay(),
                    OrderAmountDetail::getAmount, OrderAmountDetail::setWalletAmount);
         }

         if (this.accPayResultVO.getSubsidyPay() != null) {
            LeNumUtil.calcShareAmount(amountDetailList, this.accPayResultVO.getSubsidyPay(), OrderAmountDetail::getAmount, OrderAmountDetail::setSubsidyAmount);
         }

         if (this.accPayResultVO.getRedEnvelopePay() != null) {
            LeNumUtil.calcShareAmount(amountDetailList, this.accPayResultVO.getRedEnvelopePay(), OrderAmountDetail::getAmount, OrderAmountDetail::setRedEnvelopeAmount);
         }

      }
   }

   public void fillMixPayResultVO(MixPayResultVO mixPayResultVO) {
      if (mixPayResultVO.getAccPayResultVO() != null) {
         this.accPayResultVO = mixPayResultVO.getAccPayResultVO();
      }

   }

   public void fillRefundVO(PayRefundVO payRefundVO) {
      if (payRefundVO != null) {
         this.outTradeNo = payRefundVO.getOutTradeNo();
         this.tradeState = payRefundVO.getCode();
         this.tradeResult = payRefundVO.getMsg();
         this.accPayResultVO = payRefundVO.getAccPayResultVO();
      }

   }

   public static TradeChannelVO of(TradeChannel tradeChannel) {
      TradeChannelVO detailVO = (TradeChannelVO)BeanUtil.copyProperties(tradeChannel, TradeChannelVO.class, new String[0]);
      detailVO.setPayTypeName(PayTypeEnum.getDesc(detailVO.getPayType()));
      detailVO.setPayChannelName(PayChannelEnum.getDesc(detailVO.getPayChannel()));
      return detailVO;
   }

   public static TradeChannelVO of(ChannelPayVO channelPayVO) {
      TradeChannelVO detailVO = (TradeChannelVO)BeanUtil.copyProperties(channelPayVO, TradeChannelVO.class, new String[0]);
      detailVO.setPayTypeName(PayTypeEnum.getDesc(detailVO.getPayType()));
      detailVO.setPayChannelName(PayChannelEnum.getDesc(detailVO.getPayChannel()));
      detailVO.setTradeState(channelPayVO.getCode());
      detailVO.setTradeResult(channelPayVO.getMsg());
      detailVO.setAmount(channelPayVO.getRealAmount() != null && PayStateEnum.isPaidState(channelPayVO.getCode()) ? channelPayVO.getRealAmount() : channelPayVO.getAmount());
      detailVO.setAccPayResultVO(channelPayVO.getAccPayResultVO());
      detailVO.setParam(channelPayVO.getChannelParam());
      detailVO.setTradeTime(channelPayVO.getPayTime());
      return detailVO;
   }

   public Long getTradeId() {
      return this.tradeId;
   }

   public Long getTradeChannelId() {
      return this.tradeChannelId;
   }

   public Integer getTradeState() {
      return this.tradeState;
   }

   public String getTradeResult() {
      return this.tradeResult;
   }

   public Integer getPayType() {
      return this.payType;
   }

   public String getPayTypeName() {
      return this.payTypeName;
   }

   public Integer getPayChannel() {
      return this.payChannel;
   }

   public String getPayChannelName() {
      return this.payChannelName;
   }

   public BigDecimal getAmount() {
      return this.amount;
   }

   public BigDecimal getRefundAmount() {
      return this.refundAmount;
   }

   public String getOutTradeNo() {
      return this.outTradeNo;
   }

   public LocalDateTime getTradeTime() {
      return this.tradeTime;
   }

   public JsonNode getParam() {
      return this.param;
   }

   public AccPayResultVO getAccPayResultVO() {
      return this.accPayResultVO;
   }

   public TradeChannelVO setTradeId(final Long tradeId) {
      this.tradeId = tradeId;
      return this;
   }

   public TradeChannelVO setTradeChannelId(final Long tradeChannelId) {
      this.tradeChannelId = tradeChannelId;
      return this;
   }

   public TradeChannelVO setTradeState(final Integer tradeState) {
      this.tradeState = tradeState;
      return this;
   }

   public TradeChannelVO setTradeResult(final String tradeResult) {
      this.tradeResult = tradeResult;
      return this;
   }

   public TradeChannelVO setPayType(final Integer payType) {
      this.payType = payType;
      return this;
   }

   public TradeChannelVO setPayTypeName(final String payTypeName) {
      this.payTypeName = payTypeName;
      return this;
   }

   public TradeChannelVO setPayChannel(final Integer payChannel) {
      this.payChannel = payChannel;
      return this;
   }

   public TradeChannelVO setPayChannelName(final String payChannelName) {
      this.payChannelName = payChannelName;
      return this;
   }

   public TradeChannelVO setAmount(final BigDecimal amount) {
      this.amount = amount;
      return this;
   }

   public TradeChannelVO setRefundAmount(final BigDecimal refundAmount) {
      this.refundAmount = refundAmount;
      return this;
   }

   public TradeChannelVO setOutTradeNo(final String outTradeNo) {
      this.outTradeNo = outTradeNo;
      return this;
   }

   public TradeChannelVO setTradeTime(final LocalDateTime tradeTime) {
      this.tradeTime = tradeTime;
      return this;
   }

   public TradeChannelVO setParam(final JsonNode param) {
      this.param = param;
      return this;
   }

   public TradeChannelVO setAccPayResultVO(final AccPayResultVO accPayResultVO) {
      this.accPayResultVO = accPayResultVO;
      return this;
   }

}
