package com.ruoyi.system.service.impl;

import com.ruoyi.system.domain.PosOrderLinePayment;
import com.ruoyi.system.domain.PosOrderLineRefund;
import com.ruoyi.system.mapper.PosOrderLineRefundMapper;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class PosOrderLineRefundServiceImplTest {

    @Mock
    private PosOrderLineRefundMapper refundMapper;

    @InjectMocks
    private PosOrderLineRefundServiceImpl refundService;

    @Test
    void createIfAbsentReusesExistingRefundIntentForPayment() {
        PosOrderLineRefund existing = new PosOrderLineRefund();
        existing.setId(88L);
        existing.setPaymentId(70L);
        existing.setStatus("UNKNOWN");
        when(refundMapper.selectByPaymentId(70L)).thenReturn(existing);

        PosOrderLineRefund result = refundService.createIfAbsent(payment(), "USER_CANCEL");

        assertSame(existing, result);
        verify(refundMapper, never()).insert(any(PosOrderLineRefund.class));
    }

    @Test
    void newRefundIntentCopiesImmutablePaymentFacts() {
        when(refundMapper.selectByPaymentId(70L)).thenReturn(null);
        when(refundMapper.insert(any(PosOrderLineRefund.class))).thenAnswer(invocation -> {
            PosOrderLineRefund row = invocation.getArgument(0);
            row.setId(88L);
            return 1;
        });

        PosOrderLineRefund result = refundService.createIfAbsent(payment(), "STORE_CANCEL");

        assertEquals(88L, result.getId());
        assertEquals(70L, result.getPaymentId());
        assertEquals("TX-100", result.getTransactionId());
        assertEquals("CREATED", result.getStatus());
        assertEquals(280, result.getAmount());
        assertEquals("STORE_CANCEL", result.getSource());
        assertNull(result.getReconcileDeadline());
    }

    @Test
    void amountMismatchRefundUsesPersistedCapturedAmount() {
        when(refundMapper.selectByPaymentId(70L)).thenReturn(null);
        when(refundMapper.insert(any(PosOrderLineRefund.class))).thenReturn(1);
        PosOrderLinePayment payment = payment();
        payment.setStatus("AMOUNT_MISMATCH");
        payment.setCapturedAmount(100);

        PosOrderLineRefund result = refundService.createIfAbsent(payment, "AMOUNT_MISMATCH");

        assertEquals(100, result.getAmount());
    }

    private static PosOrderLinePayment payment() {
        PosOrderLinePayment payment = new PosOrderLinePayment();
        payment.setId(70L);
        payment.setDdId("DD-100");
        payment.setCredentialId(5L);
        payment.setTransactionId("TX-100");
        payment.setAmount(280);
        payment.setStatus("PAID");
        return payment;
    }
}
