package com.red.circle.order.app.command.pay.web.strategy;

import com.google.common.base.Throwables;
import com.red.circle.component.pay.clipspay.ClipspayPlaceAnOrderGoods;
import com.red.circle.component.pay.clipspay.ClipspayPlaceAnOrderParam;
import com.red.circle.component.pay.clipspay.ClipspayUtils;
import com.red.circle.component.pay.clipspay.props.ClipspayProperties;
import com.red.circle.component.pay.clipspay.service.ClipspayService;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.framework.web.props.EnvProperties;
import com.red.circle.order.app.dto.clientobject.pay.PlaceAnOrderResponseCO;
import com.red.circle.order.inner.asserts.OrderErrorCode;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.date.LocalDateUtils;
import com.red.circle.tool.core.json.JacksonUtils;
import com.red.circle.tool.core.net.IPvUtils;
import com.red.circle.tool.core.sequence.IdWorkerUtils;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * Clipspay  支付.
 *
 * @author pengliang on 2023/02/14
 */
@Slf4j
@Component("CLIPSPAY_PLACE_AN_ORDER")
@RequiredArgsConstructor
public class ClipspayPayPlaceAnOrderStrategy implements
    PayWebPlaceAnOrderStrategyV2 {

  private final EnvProperties envProperties;
  private final ClipspayService clipspayService;

  @Override
  public PlaceAnOrderResponseCO doOperation(PayPlaceAnOrderDetailsV2 details) {
    ClipspayPlaceAnOrderParam param = getPlaceAnOrderParam(details);
    if (!envProperties.isProd()) {
      log.warn("请求Clipspay参数：{}", JacksonUtils.toJson(param));
    }

    Map<String, String> response = requestApi(param);
    ResponseAssert.isTrue(OrderErrorCode.CREATE_ORDER_ERROR,
        CollectionUtils.isNotEmpty(response));

    if (!clipspayService.isSuccess(response)) {
      log.warn("ClipspayApiError:{}", JacksonUtils.toJson(response));
      ResponseAssert.failure(OrderErrorCode.CREATE_ORDER_ERROR);
    }

    // 验证签名失败
    ResponseAssert.isTrue(CommonErrorCode.VERIFY_SIGNATURE_FAILURE,
        clipspayService.validResponseSign(response));

    return new PlaceAnOrderResponseCO()
        .setTradeNo(response.get("requestNo"))
        .setOrderId(response.get("orderNo"))
        .setCurrency(details.getCurrency())
        .setCountryCode(details.getCountryCode())
        .setFactoryCode(details.getFactoryCode())
        .setFactoryChannelCode(details.getFactoryChannel())
        .setRequestUrl(response.get("redirectUrl"))
        .putRequestParam(param)
        .putResponseParam(response);
  }

  private ClipspayPlaceAnOrderParam getPlaceAnOrderParam(PayPlaceAnOrderDetailsV2 details) {
    ClipspayProperties clipspayProperties = clipspayService.getProperties();
    ClipspayPlaceAnOrderParam param = ClipspayPlaceAnOrderParam.builder()
        .requestNo(IdWorkerUtils.getIdStr())
        .version("V1.0")
        .productId("0119")
        .transId("01")
        .signType("MD5")
        .merchantNo(clipspayProperties.getMerchantNo())
        .orderDate(Objects.toString(LocalDateUtils.nowToInteger()))
        .orderNo(details.getOrderId())
        .terminalNo(clipspayProperties.getTerminalNo())
        .terNoSign(clipspayProperties.getTerminalKey())
        .amount(envProperties.isProd()
                ? details.getAmount().multiply(new BigDecimal("100")).stripTrailingZeros()
                .toPlainString()
                : "30000"
            // "30000"成功 "60000" 失败
        )
        .currencyCode(details.getCurrency())
        .notifyUrl(clipspayProperties.getNotifyUrl())
        .returnUrl(clipspayProperties.getRedirectResult())
        .shopUrl(details.getRechargeUrl())
        .ipAddress(IPvUtils.getLocalPrivateHost())
        .goodsJson(JacksonUtils.toJson(
            details.getProducts().stream().map(product ->
                    ClipspayPlaceAnOrderGoods.builder()
                        .goodsName(product.getDescribe())
                        .quantity(product.getQuantity())
                        .goodsPrice(product.getAmountUsd().stripTrailingZeros()
                            .toPlainString())
                        .build())
                .toList()
        ))
        .remark(details.getProductDescriptor())
        .build();

    param.setSignature(ClipspayUtils.sign(param, clipspayProperties.getMd5SecretKey()));
    return param;
  }


  private Map<String, String> requestApi(ClipspayPlaceAnOrderParam param) {
    try {
      return placeAnOrder(param);
    } catch (Exception ex) {
      log.error("订单创建请求失败:Error={}", Throwables.getStackTraceAsString(ex));
      log.error("订单创建请求失败:requestParam={}", JacksonUtils.toJson(param));
    }
    return CollectionUtils.newHashMap();
  }

  private HashMap<String, String> placeAnOrder(ClipspayPlaceAnOrderParam param) {
    return clipspayService.placeAnOrder(param);
  }

}
