package com.ruoyi.app.omgpay;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.Clock;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

@Component
public class OmgPaymentFormFactory {
    public static final String STAGE_GATEWAY_URL =
            "https://payment-stage.funpoint.com.tw/Cashier/AioCheckOut/V5";
    private static final DateTimeFormatter TRADE_DATE = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
    private static final ZoneId TAIPEI = ZoneId.of("Asia/Taipei");

    private final OmgPaymentProperties properties;
    private final OmgCheckMacSigner signer;
    private final Clock clock;

    @Autowired
    public OmgPaymentFormFactory(OmgPaymentProperties properties, OmgCheckMacSigner signer) {
        this(properties, signer, Clock.systemUTC());
    }

    OmgPaymentFormFactory(OmgPaymentProperties properties, OmgCheckMacSigner signer, Clock clock) {
        this.properties = properties;
        this.signer = signer;
        this.clock = clock;
    }

    public OmgPaymentForm create(String orderId, Integer amount, String merchantId,
                                 String hashKey, String hashIv, String merchantTradeNo,
                                 OmgPaymentMethod paymentMethod) {
        String safeOrderId = safeOrderReference(orderId);
        LinkedHashMap<String, String> fields = new LinkedHashMap<>();
        fields.put("MerchantID", merchantId);
        fields.put("MerchantTradeNo", merchantTradeNo);
        fields.put("MerchantTradeDate", ZonedDateTime.now(clock).withZoneSameInstant(TAIPEI).format(TRADE_DATE));
        fields.put("PaymentType", "aio");
        fields.put("TotalAmount", String.valueOf(amount));
        fields.put("TradeDesc", "Foodie order " + safeOrderId);
        fields.put("ItemName", "Order " + safeOrderId);
        fields.put("ReturnURL", properties.requireSafeReturnUrl());
        fields.put("OrderResultURL", properties.requireSafeOrderResultUrl());
        fields.put("ChoosePayment", paymentMethod.getChoosePayment());
        if (paymentMethod.isUnionPayDisabled()) {
            fields.put("UnionPay", "2");
        }
        fields.put("EncryptType", "1");
        fields.put("InvoiceMark", "N");
        fields.put("NeedExtraPaidInfo", "Y");
        Map<String, String> signedFields = Collections.unmodifiableMap(new LinkedHashMap<>(fields));
        fields.put("CheckMacValue", signer.sign(signedFields, hashKey, hashIv));
        Map<String, String> responseFields = Collections.unmodifiableMap(new LinkedHashMap<>(fields));
        return new OmgPaymentForm(STAGE_GATEWAY_URL, responseFields);
    }

    private static String safeOrderReference(String orderId) {
        String source = orderId == null ? "" : orderId;
        StringBuilder safe = new StringBuilder();
        for (int i = 0; i < source.length() && safe.length() < 64; i++) {
            char value = source.charAt(i);
            if ((value >= 'A' && value <= 'Z') || (value >= 'a' && value <= 'z')
                    || (value >= '0' && value <= '9')) {
                safe.append(value);
            }
        }
        return safe.isEmpty() ? "ORDER" : safe.toString();
    }
}
