package com.ruoyi.app.pay;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.ruoyi.app.pay.dto.LinePayQueryResult;
import com.ruoyi.app.utils.linepay.LinePayClient;
import com.ruoyi.system.domain.PosOrder;
import com.ruoyi.system.domain.PosOrderLinePayment;
import com.ruoyi.system.domain.PosOrderLineRefund;
import com.ruoyi.system.service.IPosOrderLinePaymentService;
import com.ruoyi.system.service.IPosOrderLineRefundService;
import com.ruoyi.system.service.IPosOrderService;
import com.ruoyi.system.service.IPosStoreLinePayService;
import org.junit.jupiter.api.Test;

import java.util.Date;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

class LinePaySelectionTest {

    @Test
    void unpaidQuerySelectsUniqueActiveAttemptInsteadOfNewerHistoricalReturn() {
        IPosOrderService orders = mock(IPosOrderService.class);
        IPosOrderLinePaymentService payments = mock(IPosOrderLinePaymentService.class);
        PosOrder order = new PosOrder();
        order.setDdId("DD-1"); order.setUserId(7L); order.setPayStatus(0L);
        when(orders.getOne(any(Wrapper.class))).thenReturn(order);
        PosOrderLinePayment active = attempt(2L, "WAITING_AUTH", "DD-1", 100L);
        PosOrderLinePayment historical = attempt(3L, "FAILED", null, 200L);
        when(payments.getByDdId("DD-1")).thenReturn(List.of(historical, active));
        LinePayService service = new LinePayService(orders, mock(IPosStoreLinePayService.class),
                payments, mock(IPosOrderLineRefundService.class), mock(LinePayClient.class),
                mock(LinePayFactService.class));

        LinePayQueryResult result = service.query(7L, "DD-1");

        assertEquals(2L, result.getPaymentId());
        assertEquals("WAITING_AUTH", result.getPaymentStatus());
    }

    @Test
    void multiplePaidAttemptsReturnManualReview() {
        IPosOrderService orders = mock(IPosOrderService.class);
        IPosOrderLinePaymentService payments = mock(IPosOrderLinePaymentService.class);
        PosOrder order = new PosOrder();
        order.setDdId("DD-1"); order.setUserId(7L); order.setPayStatus(1L);
        when(orders.getOne(any(Wrapper.class))).thenReturn(order);
        when(payments.getByDdId("DD-1")).thenReturn(List.of(
                attempt(2L, "PAID", "DD-1", 100L), attempt(3L, "PAID", "DD-1", 200L)));
        LinePayService service = new LinePayService(orders, mock(IPosStoreLinePayService.class),
                payments, mock(IPosOrderLineRefundService.class), mock(LinePayClient.class),
                mock(LinePayFactService.class));

        assertEquals("MANUAL_REVIEW", service.query(7L, "DD-1").getPaymentStatus());
    }

    @Test
    void paidQuerySelectsTheOnlyNotFullyRefundedAttempt() {
        IPosOrderService orders = mock(IPosOrderService.class);
        IPosOrderLinePaymentService payments = mock(IPosOrderLinePaymentService.class);
        IPosOrderLineRefundService refunds = mock(IPosOrderLineRefundService.class);
        PosOrder order = new PosOrder();
        order.setDdId("DD-1"); order.setUserId(7L); order.setPayStatus(1L);
        when(orders.getOne(any(Wrapper.class))).thenReturn(order);
        PosOrderLinePayment refunded = attempt(2L, "PAID", null, 100L);
        PosOrderLinePayment captured = attempt(3L, "PAID", "DD-1", 200L);
        when(payments.getByDdId("DD-1")).thenReturn(List.of(captured, refunded));
        PosOrderLineRefund refund = new PosOrderLineRefund();
        refund.setPaymentId(2L); refund.setStatus("REFUNDED");
        when(refunds.getByPaymentId(2L)).thenReturn(refund);
        LinePayService service = new LinePayService(orders, mock(IPosStoreLinePayService.class),
                payments, refunds, mock(LinePayClient.class), mock(LinePayFactService.class));

        LinePayQueryResult result = service.query(7L, "DD-1");

        assertEquals(3L, result.getPaymentId());
        assertEquals("PAID", result.getPaymentStatus());
    }

    private static PosOrderLinePayment attempt(Long id, String status, String active, long time) {
        PosOrderLinePayment payment = new PosOrderLinePayment();
        payment.setId(id); payment.setStatus(status); payment.setActiveDdId(active);
        payment.setCreateTime(new Date(time));
        return payment;
    }
}
