package com.red.circle.order.app.common;

import com.red.circle.framework.core.request.RequestClientEnum;
import com.red.circle.order.app.command.pay.web.strategy.PayPlaceAnOrderDetailsV2;
import com.red.circle.order.app.dto.clientobject.pay.PlaceAnOrderResponseCO;
import com.red.circle.order.infra.database.mongo.order.entity.InAppPurchaseDetails;
import com.red.circle.order.infra.database.mongo.order.entity.assist.InAppPurchaseFactory;
import com.red.circle.order.infra.database.mongo.order.entity.assist.InAppPurchaseProduct;
import com.red.circle.order.infra.database.rds.entity.order.OrderUserPurchasePay;
import com.red.circle.order.inner.model.enums.inapp.InAppPurchaseReceiptType;
import com.red.circle.order.inner.model.enums.inapp.InAppPurchaseStatus;
import com.red.circle.tool.core.date.TimestampUtils;
import com.red.circle.tool.core.text.StringUtils;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Timestamp;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * MiFaPay MySQL订单映射工具.
 */
public final class MiFaPayMysqlOrderSupport {

  public static final String FACTORY_CODE = "MIFA_PAY";
  public static final String PAY_STATUS_PREPAYMENT = "PREPAYMENT";
  public static final String PAY_STATUS_SUCCESSFUL = "SUCCESSFUL";
  public static final String PAY_STATUS_FAIL = "FAIL";
  public static final String REFUND_STATUS_NONE = "NONE";

  private MiFaPayMysqlOrderSupport() {
  }

  public static boolean isMiFaPay(String factoryCode) {
    return Objects.equals(FACTORY_CODE, factoryCode);
  }

  public static Long parseOrderId(String orderId) {
    if (StringUtils.isBlank(orderId)) {
      return null;
    }
    try {
      return Long.valueOf(orderId.trim());
    } catch (NumberFormatException ignore) {
      return null;
    }
  }

  public static OrderUserPurchasePay buildPrepaymentOrder(PayPlaceAnOrderDetailsV2 param,
      PlaceAnOrderResponseCO response, String env) {
    Timestamp now = TimestampUtils.now();
    InAppPurchaseProduct product = firstProduct(param.getProducts());
    Long referenceId = parseOrderId(param.getApplicationId());

    return new OrderUserPurchasePay()
        .setId(parseOrderId(param.getOrderId()))
        .setEvn(env)
        .setSysOrigin(param.getSysOrigin())
        .setUserId(param.getAcceptUserId())
        .setFactoryCode(param.getFactoryCode())
        .setFactoryOrderId(Objects.toString(response.getTradeNo(), ""))
        .setReferenceId(Objects.toString(param.getApplicationId(), ""))
        .setReceiptType(Objects.toString(param.getReceiptType(),
            InAppPurchaseReceiptType.PAYMENT.name()))
        .setPaymentChannel(Objects.toString(param.getChannelCode(), ""))
        .setFactoryChannel(Objects.toString(param.getFactoryChannel(), ""))
        .setProductCode(product != null ? Objects.toString(product.getCode(), "") : "")
        .setProductContent(product != null ? Objects.toString(product.getContent(), "") : "")
        .setProductDescriptor(Objects.toString(param.getProductDescriptor(), ""))
        .setPaymentUnit(Objects.toString(param.getCurrency(), ""))
        .setPaymentAmount(defaultDecimal(param.getAmount()))
        .setComputeUsdAmount(defaultDecimal(param.getAmountUsd()))
        .setComputeUsdRate(computeUsdRate(param.getAmount(), param.getAmountUsd()))
        .setGiveAwayContent("")
        .setCountryId(param.getCountry() != null ? param.getCountry().getId() : 0L)
        .setCountryCode(Objects.toString(response.getCountryCode(), param.getCountryCode()))
        .setPayCountryId(param.getPayCountry() != null ? param.getPayCountry().getId() : 0L)
        .setPayStatus(PAY_STATUS_PREPAYMENT)
        .setReason("")
        .setRefundStatus(REFUND_STATUS_NONE)
        .setReceiptDetailsId(referenceId != null ? referenceId : 0L)
        .setCreateTime(now)
        .setUpdateTime(now)
        .setCreateUser(param.getCreateUserId())
        .setUpdateUser(param.getCreateUserId());
  }

  public static InAppPurchaseDetails toInAppPurchaseDetails(OrderUserPurchasePay order) {
    List<InAppPurchaseProduct> products = StringUtils.isBlank(order.getProductCode())
        ? Collections.emptyList()
        : List.of(new InAppPurchaseProduct()
            .setId(order.getReceiptDetailsId())
            .setName(order.getProductCode())
            .setCode(order.getProductCode())
            .setDescribe(order.getProductDescriptor())
            .setContent(order.getProductContent())
            .setAmountUsd(defaultDecimal(order.getComputeUsdAmount()))
            .setQuantity(1));

    return new InAppPurchaseDetails()
        .setId(Objects.toString(order.getId(), null))
        .setReceiptType(parseReceiptType(order.getReceiptType()))
        .setTrackId(order.getReferenceId())
        .setSysOrigin(order.getSysOrigin())
        .setAcceptUserId(order.getUserId())
        .setOrderId(order.getFactoryOrderId())
        .setEnv(order.getEvn())
        .setFactory(new InAppPurchaseFactory()
            .setPlatform(RequestClientEnum.H5.getClientName())
            .setFactoryCode(order.getFactoryCode())
            .setFactoryChannelCode(order.getPaymentChannel()))
        .setProducts(products)
        .setProductDescriptor(order.getProductDescriptor())
        .setCountryCode(order.getCountryCode())
        .setCurrency(order.getPaymentUnit())
        .setAmount(defaultDecimal(order.getPaymentAmount()))
        .setAmountUsd(defaultDecimal(order.getComputeUsdAmount()))
        .setTrialPeriod(Boolean.FALSE)
        .setStatus(toInAppPurchaseStatus(order.getPayStatus()))
        .setReason(order.getReason())
        .setCreateTime(order.getCreateTime())
        .setUpdateTime(order.getUpdateTime())
        .setCreateUser(order.getCreateUser());
  }

  public static InAppPurchaseStatus toInAppPurchaseStatus(String payStatus) {
    if (Objects.equals(PAY_STATUS_SUCCESSFUL, payStatus)) {
      return InAppPurchaseStatus.SUCCESS;
    }
    if (Objects.equals(PAY_STATUS_FAIL, payStatus)) {
      return InAppPurchaseStatus.FAIL;
    }
    return InAppPurchaseStatus.CREATE;
  }

  public static boolean isSuccess(String payStatus) {
    return Objects.equals(PAY_STATUS_SUCCESSFUL, payStatus);
  }

  public static boolean isFinished(String payStatus) {
    return isSuccess(payStatus) || Objects.equals(PAY_STATUS_FAIL, payStatus);
  }

  private static String computeUsdRate(BigDecimal paymentAmount, BigDecimal usdAmount) {
    if (paymentAmount == null || usdAmount == null || BigDecimal.ZERO.compareTo(usdAmount) == 0) {
      return "";
    }
    return paymentAmount.divide(usdAmount, 8, RoundingMode.HALF_UP)
        .stripTrailingZeros()
        .toPlainString();
  }

  private static InAppPurchaseProduct firstProduct(List<InAppPurchaseProduct> products) {
    return products == null || products.isEmpty() ? null : products.get(0);
  }

  private static InAppPurchaseReceiptType parseReceiptType(String receiptType) {
    if (Objects.equals(InAppPurchaseReceiptType.RECEIPT.name(), receiptType)) {
      return InAppPurchaseReceiptType.RECEIPT;
    }
    return InAppPurchaseReceiptType.PAYMENT;
  }

  private static BigDecimal defaultDecimal(BigDecimal value) {
    return value != null ? value : BigDecimal.ZERO;
  }
}
