package com.ruoyi.web.modules.trading.service.impl;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.text.ParseException;
import java.util.Collections;
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.mapper.BizEntryIsolationAllocMapper;
import com.ruoyi.web.modules.trading.mapper.BizEntryIsolationMapper;
import com.ruoyi.web.modules.trading.support.EntryIsolationReferenceChecker;
import com.ruoyi.web.modules.trading.support.EntryIsolationRules;
import com.ruoyi.web.modules.trading.support.EntryIsolationValidation;
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("BizEntryIsolationServiceImpl")
class BizEntryIsolationServiceImplTest
{
    @Mock
    private BizEntryIsolationMapper entryMapper;

    @Mock
    private BizEntryIsolationAllocMapper allocMapper;

    @Mock
    private EntryIsolationValidation validation;

    @Mock
    private EntryIsolationReferenceChecker referenceChecker;

    @InjectMocks
    private BizEntryIsolationServiceImpl service;

    @Test
    @DisplayName("新增主从落库")
    void insert() throws ParseException
    {
        doAnswer(inv -> {
            BizEntryIsolation row = inv.getArgument(0);
            row.setExpectedReleaseDate(EntryIsolationTestSamples.expectedReleaseDate());
            return null;
        }).when(validation).prepareAndValidateForSave(any());
        when(entryMapper.insertBizEntryIsolation(any())).thenAnswer(inv -> {
            BizEntryIsolation row = inv.getArgument(0);
            row.setId(10L);
            return 1;
        });
        when(allocMapper.batchInsertAlloc(any())).thenReturn(2);
        BizEntryIsolation row = EntryIsolationTestSamples.validSaveRow();
        assertEquals(1, service.insertBizEntryIsolation(row));
        verify(entryMapper).insertBizEntryIsolation(argThat(r ->
                EntryIsolationRules.DEL_FLAG_NORMAL.equals(r.getDelFlag())
                        && r.getExpectedReleaseDate() != null));
        verify(allocMapper).batchInsertAlloc(argThat(list -> list != null && list.size() == 2));
    }

    @Test
    @DisplayName("修改覆盖分圈")
    void updateReplacesAlloc() throws ParseException
    {
        BizEntryIsolation db = new BizEntryIsolation();
        db.setId(10L);
        db.setDelFlag(EntryIsolationRules.DEL_FLAG_NORMAL);
        when(entryMapper.selectBizEntryIsolationById(10L)).thenReturn(db);
        when(entryMapper.updateBizEntryIsolation(any())).thenReturn(1);
        when(allocMapper.batchInsertAlloc(any())).thenReturn(2);
        BizEntryIsolation row = EntryIsolationTestSamples.validSaveRow();
        row.setId(10L);
        assertEquals(1, service.updateBizEntryIsolation(row));
        verify(allocMapper).deleteAllocByEntryId(10L);
        verify(allocMapper).batchInsertAlloc(any());
    }

    @Test
    @DisplayName("逻辑删除")
    void remove()
    {
        BizEntryIsolation db = new BizEntryIsolation();
        db.setId(10L);
        db.setDelFlag(EntryIsolationRules.DEL_FLAG_NORMAL);
        when(entryMapper.selectBizEntryIsolationByIdAny(10L)).thenReturn(db);
        when(referenceChecker.hasReference(10L)).thenReturn(false);
        when(entryMapper.logicDeleteBizEntryIsolationByIds(any(), any())).thenReturn(1);
        assertEquals(1, service.deleteBizEntryIsolationByIds(new Long[] { 10L }, "tester"));
    }

    @Test
    @DisplayName("删除有关联")
    void removeBlocked()
    {
        BizEntryIsolation db = new BizEntryIsolation();
        db.setId(10L);
        db.setDelFlag(EntryIsolationRules.DEL_FLAG_NORMAL);
        when(entryMapper.selectBizEntryIsolationByIdAny(10L)).thenReturn(db);
        when(referenceChecker.hasReference(10L)).thenReturn(true);
        assertThrows(ServiceException.class,
                () -> service.deleteBizEntryIsolationByIds(new Long[] { 10L }, "tester"));
        verify(entryMapper, never()).logicDeleteBizEntryIsolationByIds(any(), any());
    }

    @Test
    @DisplayName("详情含分圈")
    void detail()
    {
        BizEntryIsolation db = new BizEntryIsolation();
        db.setId(10L);
        db.setEarTags("E001,E002");
        when(entryMapper.selectBizEntryIsolationById(10L)).thenReturn(db);
        when(allocMapper.selectAllocListByEntryId(10L))
                .thenReturn(Collections.singletonList(new com.ruoyi.web.modules.trading.domain.BizEntryIsolationAlloc()));
        BizEntryIsolation result = service.selectBizEntryIsolationById(10L);
        assertEquals(2, result.getEarTagList().size());
        assertEquals(1, result.getPenAllocList().size());
    }
}
