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

import com.red.circle.component.mq.MessageEvent;
import com.red.circle.mq.business.model.event.pay.BuySuccessEvent;
import com.red.circle.mq.business.model.event.pay.RechargeSuccessEvent;
import com.red.circle.mq.rocket.business.service.MessageSenderService;
import com.red.circle.mq.rocket.business.streams.RechargeSuccessSink;
import com.red.circle.order.infra.database.mongo.order.entity.InAppPurchaseDetails;
import com.red.circle.order.infra.database.mongo.order.entity.assist.InAppPurchaseProduct;
import com.red.circle.order.inner.model.enums.PayApplicationCommodityType;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Timestamp;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class RechargeSuccessEventPublisher {

  private static final String GOOGLE = "GOOGLE";
  private static final String APPLE = "APPLE";
  private static final String THIRD_PARTY = "THIRD_PARTY";
  private static final String UNKNOWN = "UNKNOWN";

  private final ObjectProvider<MessageSenderService> messageSenderServiceProvider;

  @Value("${recharge.success.mq.enabled:true}")
  private boolean mqEnabled;

  @Value("${recharge.success.mq.topic:RC_DEFAULT_APP_ORDINARY}")
  private String mqTopic;

  @Value("${recharge.success.mq.tag:" + RechargeSuccessSink.TAG + "}")
  private String mqTag;

  public RechargeSuccessEventPublisher(ObjectProvider<MessageSenderService> messageSenderServiceProvider) {
    this.messageSenderServiceProvider = messageSenderServiceProvider;
  }

  public void reportAppPurchaseRecharge(BuySuccessEvent event) {
    if (Objects.isNull(event)) {
      return;
    }
    Long userId = event.getAcceptUserId();
    Long purchaseHistoryId = event.getPurchaseHistoryId();
    BigDecimal amountUsd = Objects.nonNull(event.getProductConfig())
        ? event.getProductConfig().getUnitPrice()
        : null;
    Long amountCents = toCents(amountUsd);
    if (Objects.isNull(userId) || Objects.isNull(purchaseHistoryId) || !positive(amountCents)) {
      return;
    }

    String sourceOrderId = String.valueOf(purchaseHistoryId);
    String payPlatform = normalizePayPlatform(defaultIfBlank(event.getPayPlatform(), event.getPlatform()));
    String paymentMethod = classifyPaymentMethod(payPlatform);
    String appVersion = defaultIfBlank(event.getAppVersion(), "");
    String productId = Objects.nonNull(event.getProductConfig())
        ? defaultIfBlank(event.getProductConfig().getProductId(), event.getOrigin())
        : defaultIfBlank(event.getOrigin(), "");
    String googleProductId = Objects.equals(GOOGLE, payPlatform) ? productId : "";

    Map<String, Object> payload = new HashMap<>();
    payload.put("payerUserId", event.getUserId());
    payload.put("acceptUserId", userId);
    payload.put("purchaseHistoryId", purchaseHistoryId);
    payload.put("candyQuantity", event.getCandyQuantity());
    payload.put("platform", event.getPlatform());
    payload.put("payPlatform", event.getPayPlatform());
    payload.put("appVersion", event.getAppVersion());
    payload.put("productId", productId);
    payload.put("googleProductId", googleProductId);

    publish(new RechargeSuccessEvent()
        .setEventId("RECHARGE_SUCCESS:" + paymentMethod + ":" + sourceOrderId)
        .setSysOrigin(event.getSysOrigin())
        .setUserId(userId)
        .setAmountCents(amountCents)
        .setAmountUsd(formatAmount(amountUsd))
        .setCurrency("USD")
        .setPayPlatform(payPlatform)
        .setPaymentMethod(paymentMethod)
        .setProductId(productId)
        .setGoogleProductId(googleProductId)
        .setAppVersion(appVersion)
        .setSourceOrderId(sourceOrderId)
        .setOrderId(sourceOrderId)
        .setOccurredAt(toInstantString(event.getBuyDateTime()))
        .setPayload(payload));
  }

  public void reportPaymentRecharge(InAppPurchaseDetails order) {
    if (Objects.isNull(order) || !order.receiptTypeEqPayment()) {
      return;
    }
    InAppPurchaseProduct product = order.firstProduct();
    if (Objects.isNull(product) || !PayApplicationCommodityType.GOLD.eq(product.getCode())) {
      return;
    }
    String payPlatform = normalizePayPlatform(Objects.nonNull(order.getFactory()) ? order.getFactory().getFactoryCode() : "");
    String paymentMethod = classifyPaymentMethod(payPlatform);

    BigDecimal amountUsd = firstPositive(order.getAmountUsd(), product.getAmountUsd());
    Long amountCents = toCents(amountUsd);
    if (Objects.isNull(order.getAcceptUserId()) || isBlank(order.getId()) || !positive(amountCents)) {
      return;
    }

    Map<String, Object> payload = new HashMap<>();
    payload.put("trackId", order.getTrackId());
    payload.put("sourceOrderId", order.getId());
    payload.put("orderId", order.getOrderId());
    payload.put("factoryCode", payPlatform);
    payload.put("factoryChannelCode", Objects.nonNull(order.getFactory()) ? order.getFactory().getFactoryChannelCode() : null);
    payload.put("platform", Objects.nonNull(order.getFactory()) ? order.getFactory().getPlatform() : null);
    payload.put("productCode", product.getCode());
    payload.put("productContent", product.getContent());
    String appVersion = appVersionFromMetadata(order);
    payload.put("appVersion", appVersion);
    String productId = defaultIfBlank(order.getTrackId(), "");
    String googleProductId = Objects.equals(GOOGLE, payPlatform) ? productId : "";
    payload.put("productId", productId);
    payload.put("googleProductId", googleProductId);

    publish(new RechargeSuccessEvent()
        .setEventId("RECHARGE_SUCCESS:" + paymentMethod + ":" + payPlatform + ":" + order.getId())
        .setSysOrigin(order.getSysOrigin())
        .setUserId(order.getAcceptUserId())
        .setAmountCents(amountCents)
        .setAmountUsd(formatAmount(amountUsd))
        .setCurrency(defaultIfBlank(order.getCurrency(), "USD"))
        .setPayPlatform(payPlatform)
        .setPaymentMethod(paymentMethod)
        .setProductId(productId)
        .setGoogleProductId(googleProductId)
        .setAppVersion(appVersion)
        .setSourceOrderId(order.getId())
        .setOrderId(defaultIfBlank(order.getOrderId(), order.getId()))
        .setOccurredAt(firstTime(order.getPurchaseDateMs(), order.getUpdateTime(), order.getCreateTime()))
        .setPayload(payload));
  }

  private void publish(RechargeSuccessEvent event) {
    if (!mqEnabled) {
      return;
    }
    try {
      MessageSenderService senderService = messageSenderServiceProvider.getIfAvailable();
      if (Objects.isNull(senderService)) {
        log.warn("Recharge success mq sender missing, skip event report. eventId={}", event.getEventId());
        return;
      }
      senderService.sendEventMessage(MessageEvent.builder()
          .consumeId(event.getEventId())
          .topicString(defaultIfBlank(mqTopic, "RC_DEFAULT_APP_ORDINARY"))
          .tag(defaultIfBlank(mqTag, RechargeSuccessSink.TAG))
          .body(event)
          .build());
    } catch (Exception e) {
      log.warn("Recharge success mq report error. eventId={}", event.getEventId(), e);
    }
  }

  private String normalizePayPlatform(String value) {
    String normalized = Objects.toString(value, "").trim().toUpperCase();
    return normalized.isEmpty() ? UNKNOWN : normalized;
  }

  private String classifyPaymentMethod(String payPlatform) {
    if (Objects.equals(GOOGLE, payPlatform)) {
      return GOOGLE;
    }
    if (Objects.equals(APPLE, payPlatform)) {
      return APPLE;
    }
    if (Objects.equals(UNKNOWN, payPlatform)) {
      return UNKNOWN;
    }
    return THIRD_PARTY;
  }

  private String appVersionFromMetadata(InAppPurchaseDetails order) {
    if (Objects.isNull(order) || Objects.isNull(order.getMetadata())) {
      return "";
    }
    return defaultIfBlank(order.getMetadata().get("appVersion"), "");
  }

  private Long toCents(BigDecimal amount) {
    if (Objects.isNull(amount) || amount.compareTo(BigDecimal.ZERO) <= 0) {
      return null;
    }
    return amount.multiply(BigDecimal.valueOf(100)).setScale(0, RoundingMode.HALF_UP).longValue();
  }

  private BigDecimal firstPositive(BigDecimal first, BigDecimal second) {
    if (Objects.nonNull(first) && first.compareTo(BigDecimal.ZERO) > 0) {
      return first;
    }
    return second;
  }

  private boolean positive(Long value) {
    return Objects.nonNull(value) && value > 0;
  }

  private String toInstantString(Timestamp timestamp) {
    return Objects.nonNull(timestamp) ? timestamp.toInstant().toString() : Instant.now().toString();
  }

  private String firstTime(Timestamp first, Timestamp second, Timestamp third) {
    if (Objects.nonNull(first)) {
      return first.toInstant().toString();
    }
    if (Objects.nonNull(second)) {
      return second.toInstant().toString();
    }
    if (Objects.nonNull(third)) {
      return third.toInstant().toString();
    }
    return Instant.now().toString();
  }

  private String formatAmount(BigDecimal amount) {
    return Objects.isNull(amount) ? null : amount.stripTrailingZeros().toPlainString();
  }

  private String defaultIfBlank(String value, String fallback) {
    return isBlank(value) ? fallback : value.trim();
  }

  private boolean isBlank(String value) {
    return Objects.toString(value, "").trim().isEmpty();
  }
}
