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

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

import java.text.ParseException;
import java.util.Arrays;
import java.util.Collections;
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;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.web.modules.trading.IsolationPatrolTestSamples;
import com.ruoyi.web.modules.trading.domain.BizIsolationPatrol;
import com.ruoyi.web.modules.trading.mapper.BizIsolationPatrolMapper;
import com.ruoyi.web.modules.trading.mapper.BizIsolationPenMapper;

@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
@DisplayName("PatrolValidation")
class PatrolValidationTest
{
    @Mock
    private BizIsolationPatrolMapper bizIsolationPatrolMapper;

    @Mock
    private BizIsolationPenMapper bizIsolationPenMapper;

    @InjectMocks
    private PatrolValidation patrolValidation;

    @BeforeEach
    void stubInStock()
    {
        when(bizIsolationPatrolMapper.countPenInStock(IsolationPatrolTestSamples.PEN_ID_1)).thenReturn(1);
        when(bizIsolationPenMapper.selectBizIsolationPenById(IsolationPatrolTestSamples.PEN_ID_1))
                .thenReturn(IsolationPatrolTestSamples.activePen());
        when(bizIsolationPatrolMapper.selectAllocEarTagRowsForPen(IsolationPatrolTestSamples.PEN_ID_1))
                .thenReturn(IsolationPatrolTestSamples.allocEarTagRows());
    }

    @Test
    @DisplayName("ZCZX-GLXCDJ-UT-001 耳标逗号拆分")
    void ut001_earTagParse()
    {
        assertEquals(Arrays.asList("A", "B"), EarTagCodec.parse("A,B"));
    }

    @Test
    @DisplayName("ZCZX-GLXCDJ-UT-003 P1 数量为0有耳标失败")
    void ut003_p1Fail()
    {
        assertThrows(ServiceException.class,
                () -> PatrolValidation.validateConsistency(0, Arrays.asList("E1")));
    }

    @Test
    @DisplayName("ZCZX-GLXCDJ-UT-004 P1 数量为0通过")
    void ut004_p1Pass()
    {
        assertDoesNotThrow(() -> PatrolValidation.validateConsistency(0, Collections.emptyList()));
    }

    @Test
    @DisplayName("ZCZX-GLXCDJ-UT-005 P2 数量与耳标不等")
    void ut005_p2Fail()
    {
        assertThrows(ServiceException.class,
                () -> PatrolValidation.validateConsistency(2, Collections.singletonList("E001")));
    }

    @Test
    @DisplayName("ZCZX-GLXCDJ-UT-006 P2 数量与耳标相等")
    void ut006_p2Pass()
    {
        assertDoesNotThrow(() -> PatrolValidation.validateConsistency(2,
                Arrays.asList("E001", "E002")));
    }

    @Test
    @DisplayName("ZCZX-GLXCDJ-UT-007 P3 耳标不在栏")
    void ut007_p3NotInPen() throws ParseException
    {
        BizIsolationPatrol row = IsolationPatrolTestSamples.abnormalSaveRow();
        row.setEarTagList(Arrays.asList("E009", "E010"));
        assertThrows(ServiceException.class, () -> patrolValidation.prepareAndValidateForSave(row));
    }

    @Test
    @DisplayName("ZCZX-GLXCDJ-UT-009 过期圈位不在栏")
    void ut009_penNotInStock()
    {
        when(bizIsolationPatrolMapper.countPenInStock(anyLong())).thenReturn(0);
        assertFalse(patrolValidation.isPenInStock(IsolationPatrolTestSamples.PEN_ID_1));
    }

    @Test
    @DisplayName("ZCZX-GLXCDJ-UT-010 有效圈位在栏")
    void ut010_penInStock()
    {
        assertTrue(patrolValidation.isPenInStock(IsolationPatrolTestSamples.PEN_ID_1));
    }

    @Test
    @DisplayName("ZCZX-GLXCDJ-UT-011 合并分圈耳标")
    void ut011_mergeEarTags()
    {
        assertEquals(IsolationPatrolTestSamples.inStockTags(),
                patrolValidation.listInStockEarTags(IsolationPatrolTestSamples.PEN_ID_1));
    }

    @Test
    @DisplayName("ZCZX-GLXCDJ-UT-012 巡查时间晚于当前")
    void ut012_futurePatrolTime() throws ParseException
    {
        BizIsolationPatrol row = IsolationPatrolTestSamples.normalSaveRow();
        row.setPatrolTime(IsolationPatrolTestSamples.parseDateTime("2099-01-01 00:00:00"));
        assertThrows(ServiceException.class, () -> patrolValidation.prepareAndValidateForSave(row));
    }

    @Test
    @DisplayName("ZCZX-GLXCDJ-UT-014 文案长度")
    void ut014_descLength() throws ParseException
    {
        BizIsolationPatrol row = IsolationPatrolTestSamples.normalSaveRow();
        row.setContentDesc("");
        assertThrows(ServiceException.class, () -> patrolValidation.prepareAndValidateForSave(row));
        row.setContentDesc("巡查结果正常");
        StringBuilder longText = new StringBuilder();
        for (int i = 0; i < 201; i++)
        {
            longText.append('a');
        }
        row.setContentDesc(longText.toString());
        assertThrows(ServiceException.class, () -> patrolValidation.prepareAndValidateForSave(row));
    }

    @Test
    @DisplayName("ZCZX-GLXCDJ-UT-016 照片后缀")
    void ut016_photoExt()
    {
        assertTrue(IsolationPatrolRules.isPhotoExtensionAllowed("a.png"));
        assertFalse(IsolationPatrolRules.isPhotoExtensionAllowed("a.exe"));
    }

    @Test
    @DisplayName("ZCZX-GLXCDJ-UT-004 合法正常保存")
    void validNormalSave() throws ParseException
    {
        assertDoesNotThrow(() -> patrolValidation.prepareAndValidateForSave(
                IsolationPatrolTestSamples.normalSaveRow()));
    }
}
