package com.ruoyi.app.omgpay;

import com.ruoyi.app.omgpay.dto.OmgQueryPaymentResponse;
import org.springframework.stereotype.Service;

import static com.ruoyi.app.omgpay.OmgPaymentErrorCode.ORDER_ALREADY_PAID;
import static com.ruoyi.app.omgpay.OmgPaymentErrorCode.PAYMENT_METHOD_INVALID;
import static com.ruoyi.app.omgpay.OmgPaymentErrorCode.PAYMENT_QUERY_NOT_AVAILABLE;
import static com.ruoyi.app.omgpay.OmgPaymentErrorCode.PAYMENT_RETRY_NOT_AVAILABLE;

/** Verifies the gateway state before replacing an abandoned payment attempt. */
@Service
public class OmgPaymentRetryService {
    private final OmgPaymentQueryService queryService;
    private final OmgPaymentCreateService createService;

    public OmgPaymentRetryService(OmgPaymentQueryService queryService,
                                  OmgPaymentCreateService createService) {
        this.queryService = queryService;
        this.createService = createService;
    }

    public OmgPaymentCreateOutcome retry(Long userId, String orderId, OmgPaymentMethod paymentMethod) {
        if (paymentMethod == null) {
            throw business(PAYMENT_METHOD_INVALID);
        }
        OmgQueryPaymentResponse query;
        try {
            query = queryService.query(userId, orderId);
        } catch (OmgPaymentBusinessException exception) {
            if (exception.getCode() != PAYMENT_QUERY_NOT_AVAILABLE) {
                throw exception;
            }
            // A terminal attempt (FAILED/SUPERSEDED by auto-compensation) has released its
            // active pointer, so query has nothing to reconcile; a still-unpaid order is then
            // equivalent to a first-time payment, and create re-validates order and concurrency.
            return createService.create(userId, orderId, paymentMethod);
        }
        if (query == null || query.status() == null) {
            throw business(PAYMENT_RETRY_NOT_AVAILABLE);
        }
        if ("PAID".equals(query.status())) {
            throw business(ORDER_ALREADY_PAID);
        }
        if ("FAILED".equals(query.status())) {
            return createService.create(userId, orderId, paymentMethod);
        }
        if ("UNPAID".equals(query.status()) && isBlank(query.paymentType())) {
            return createService.replaceActiveForRetry(userId, orderId, query.merchantTradeNo(), paymentMethod);
        }
        throw business(PAYMENT_RETRY_NOT_AVAILABLE);
    }

    private static boolean isBlank(String value) {
        return value == null || value.isBlank();
    }

    private static OmgPaymentBusinessException business(OmgPaymentErrorCode code) {
        return new OmgPaymentBusinessException(code);
    }
}
