package com.ruoyi.web.modules.trading.support;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.when;

import java.text.ParseException;
import java.util.Arrays;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.web.modules.trading.EntryIsolationTestSamples;
import com.ruoyi.web.modules.trading.domain.BizEntryIsolation;
import com.ruoyi.web.modules.trading.domain.BizEntryIsolationAlloc;
import com.ruoyi.web.modules.trading.mapper.BizIsolationPenMapper;
import com.ruoyi.web.modules.trading.mapper.BizSupplierMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
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 org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;

@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
@DisplayName("EntryIsolationValidation")
class EntryIsolationValidationTest
{
    @Mock
    private BizSupplierMapper bizSupplierMapper;

    @Mock
    private BizIsolationPenMapper bizIsolationPenMapper;

    @InjectMocks
    private EntryIsolationValidation validation;

    @BeforeEach
    void stubFk()
    {
        when(bizSupplierMapper.selectBizSupplierById(EntryIsolationTestSamples.SUPPLIER_ID))
                .thenReturn(EntryIsolationTestSamples.activeSupplier());
        when(bizIsolationPenMapper.selectBizIsolationPenById(EntryIsolationTestSamples.PEN_ID_1))
                .thenReturn(EntryIsolationTestSamples.activePen(EntryIsolationTestSamples.PEN_ID_1, "01"));
        when(bizIsolationPenMapper.selectBizIsolationPenById(EntryIsolationTestSamples.PEN_ID_2))
                .thenReturn(EntryIsolationTestSamples.activePen(EntryIsolationTestSamples.PEN_ID_2, "02"));
        when(bizIsolationPenMapper.selectBizIsolationPenByIdAny(EntryIsolationTestSamples.PEN_ID_1))
                .thenReturn(EntryIsolationTestSamples.activePen(EntryIsolationTestSamples.PEN_ID_1, "01"));
    }

    @Test
    @DisplayName("合法全量")
    void valid() throws ParseException
    {
        assertDoesNotThrow(() -> validation.prepareAndValidateForSave(EntryIsolationTestSamples.validSaveRow()));
    }

    @Test
    @DisplayName("R1 数量≠耳标数")
    void r1()
    {
        BizEntryIsolation row = new BizEntryIsolation();
        row.setEntryTime(new java.util.Date());
        row.setSupplierId(EntryIsolationTestSamples.SUPPLIER_ID);
        row.setCertNo("QZ1");
        row.setQuantity(3);
        row.setEarTagList(Arrays.asList("E1", "E2"));
        row.setIsolationDays(7);
        row.setPenAllocList(Arrays.asList(alloc(EntryIsolationTestSamples.PEN_ID_1, "E1"),
                alloc(EntryIsolationTestSamples.PEN_ID_2, "E2")));
        assertThrows(ServiceException.class, () -> validation.prepareAndValidateForSave(row));
    }

    @Test
    @DisplayName("R4 跨圈重复耳标")
    void r4()
    {
        BizEntryIsolation row = new BizEntryIsolation();
        row.setEntryTime(new java.util.Date());
        row.setSupplierId(EntryIsolationTestSamples.SUPPLIER_ID);
        row.setCertNo("QZ1");
        row.setQuantity(2);
        row.setEarTagList(Arrays.asList("E1", "E2"));
        row.setIsolationDays(7);
        row.setPenAllocList(Arrays.asList(alloc(EntryIsolationTestSamples.PEN_ID_1, "E1"),
                alloc(EntryIsolationTestSamples.PEN_ID_2, "E1")));
        assertThrows(ServiceException.class, () -> validation.prepareAndValidateForSave(row));
    }

    @Test
    @DisplayName("分圈为空")
    void emptyAlloc()
    {
        BizEntryIsolation row = new BizEntryIsolation();
        row.setEntryTime(new java.util.Date());
        row.setSupplierId(EntryIsolationTestSamples.SUPPLIER_ID);
        row.setCertNo("QZ1");
        row.setQuantity(1);
        row.setEarTagList(Arrays.asList("E1"));
        row.setIsolationDays(7);
        row.setPenAllocList(Arrays.asList());
        assertThrows(ServiceException.class, () -> validation.prepareAndValidateForSave(row));
    }

    @Test
    @DisplayName("重复圈位")
    void duplicatePen()
    {
        BizEntryIsolation row = new BizEntryIsolation();
        row.setEntryTime(new java.util.Date());
        row.setSupplierId(EntryIsolationTestSamples.SUPPLIER_ID);
        row.setCertNo("QZ1");
        row.setQuantity(2);
        row.setEarTagList(Arrays.asList("E1", "E2"));
        row.setIsolationDays(7);
        row.setPenAllocList(Arrays.asList(alloc(EntryIsolationTestSamples.PEN_ID_1, "E1"),
                alloc(EntryIsolationTestSamples.PEN_ID_1, "E2")));
        assertThrows(ServiceException.class, () -> validation.prepareAndValidateForSave(row));
    }

    @Test
    @DisplayName("供应商已删")
    void supplierGone()
    {
        when(bizSupplierMapper.selectBizSupplierById(anyLong())).thenReturn(null);
        assertThrows(ServiceException.class,
                () -> validation.prepareAndValidateForSave(sampleMinimal()));
    }

    private static BizEntryIsolation sampleMinimal()
    {
        BizEntryIsolation row = new BizEntryIsolation();
        row.setEntryTime(new java.util.Date());
        row.setSupplierId(99L);
        row.setCertNo("QZ1");
        row.setQuantity(1);
        row.setEarTagList(Arrays.asList("E1"));
        row.setIsolationDays(7);
        row.setPenAllocList(Arrays.asList(alloc(EntryIsolationTestSamples.PEN_ID_1, "E1")));
        return row;
    }

    private static BizEntryIsolationAlloc alloc(Long penId, String... tags)
    {
        BizEntryIsolationAlloc a = new BizEntryIsolationAlloc();
        a.setPenId(penId);
        a.setEarTagList(Arrays.asList(tags));
        return a;
    }
}
