package com.ycwl.basic.face.pipeline.stages;

import com.ycwl.basic.face.pipeline.core.FaceMatchingContext;
import com.ycwl.basic.pipeline.core.StageResult;
import com.ycwl.basic.model.pc.face.entity.FaceEntity;
import com.ycwl.basic.model.pc.source.entity.MemberSourceEntity;
import com.ycwl.basic.model.task.resp.SearchFaceRespVo;
import com.ycwl.basic.service.pc.processor.SourceRelationProcessor;
import org.junit.jupiter.api.BeforeEach;
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 java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.Mockito.*;

/**
 * BuildSourceRelationStage 单元测试
 */
@ExtendWith(MockitoExtension.class)
class BuildSourceRelationStageTest {

    @Mock
    private SourceRelationProcessor sourceRelationProcessor;

    @InjectMocks
    private BuildSourceRelationStage stage;

    private FaceMatchingContext context;
    private FaceEntity face;

    @BeforeEach
    void setUp() {
        context = FaceMatchingContext.forAutoMatching(1L, true);

        face = new FaceEntity();
        face.setId(1L);
        face.setMemberId(100L);
        face.setScenicId(10L);

        context.setFace(face);
    }

    @Test
    void testExecute_Success() {
        // Given
        List<Long> sampleListIds = Arrays.asList(101L, 102L, 103L);
        context.setSampleListIds(sampleListIds);

        List<MemberSourceEntity> memberSourceList = createMemberSourceList(3);
        when(sourceRelationProcessor.processMemberSources(sampleListIds, face))
                .thenReturn(memberSourceList);

        // When
        StageResult<FaceMatchingContext> result = stage.execute(context);

        // Then
        assertTrue(result.isSuccess());
        assertTrue(result.getMessage().contains("构建了3个源文件关联"));
        assertEquals(memberSourceList, context.getMemberSourceList());
        verify(sourceRelationProcessor, times(1)).processMemberSources(sampleListIds, face);
    }

    @Test
    void testExecute_SampleListIdsNull_FromSearchResult() {
        // Given: sampleListIds为null,但searchResult有值
        context.setSampleListIds(null);

        SearchFaceRespVo searchResult = new SearchFaceRespVo();
        searchResult.setSampleListIds(Arrays.asList(101L, 102L));
        context.setSearchResult(searchResult);

        List<MemberSourceEntity> memberSourceList = createMemberSourceList(2);
        when(sourceRelationProcessor.processMemberSources(anyList(), any()))
                .thenReturn(memberSourceList);

        // When
        StageResult<FaceMatchingContext> result = stage.execute(context);

        // Then
        assertTrue(result.isSuccess());
        assertEquals(Arrays.asList(101L, 102L), context.getSampleListIds()); // 从searchResult复制过来
        verify(sourceRelationProcessor, times(1)).processMemberSources(anyList(), any());
    }

    @Test
    void testExecute_SampleListIdsEmpty_Skipped() {
        // Given
        context.setSampleListIds(new ArrayList<>());
        context.setSearchResult(null);

        // When
        StageResult<FaceMatchingContext> result = stage.execute(context);

        // Then
        assertTrue(result.isSkipped());
        assertTrue(result.getMessage().contains("sampleListIds为空"));
        verify(sourceRelationProcessor, never()).processMemberSources(anyList(), any());
    }

    @Test
    void testExecute_BothSampleListIdsAndSearchResultEmpty_Skipped() {
        // Given
        context.setSampleListIds(null);

        SearchFaceRespVo searchResult = new SearchFaceRespVo();
        searchResult.setSampleListIds(null);
        context.setSearchResult(searchResult);

        // When
        StageResult<FaceMatchingContext> result = stage.execute(context);

        // Then
        assertTrue(result.isSkipped());
        verify(sourceRelationProcessor, never()).processMemberSources(anyList(), any());
    }

    @Test
    void testExecute_ProcessorReturnsNull_Skipped() {
        // Given
        List<Long> sampleListIds = Arrays.asList(101L, 102L);
        context.setSampleListIds(sampleListIds);

        when(sourceRelationProcessor.processMemberSources(sampleListIds, face))
                .thenReturn(null);

        // When
        StageResult<FaceMatchingContext> result = stage.execute(context);

        // Then
        assertTrue(result.isSkipped());
        assertTrue(result.getMessage().contains("未找到有效的源文件"));
        assertNull(context.getMemberSourceList());
    }

    @Test
    void testExecute_ProcessorReturnsEmpty_Skipped() {
        // Given
        List<Long> sampleListIds = Arrays.asList(101L, 102L);
        context.setSampleListIds(sampleListIds);

        when(sourceRelationProcessor.processMemberSources(sampleListIds, face))
                .thenReturn(new ArrayList<>());

        // When
        StageResult<FaceMatchingContext> result = stage.execute(context);

        // Then
        assertTrue(result.isSkipped());
        assertTrue(result.getMessage().contains("未找到有效的源文件"));
    }

    @Test
    void testExecute_ProcessorThrowsException_Degraded() {
        // Given
        List<Long> sampleListIds = Arrays.asList(101L, 102L);
        context.setSampleListIds(sampleListIds);

        when(sourceRelationProcessor.processMemberSources(sampleListIds, face))
                .thenThrow(new RuntimeException("Processing error"));

        // When
        StageResult<FaceMatchingContext> result = stage.execute(context);

        // Then
        assertTrue(result.isDegraded()); // 降级处理
        assertTrue(result.getMessage().contains("构建源文件关联失败"));
        verify(sourceRelationProcessor, times(1)).processMemberSources(sampleListIds, face);
    }

    @Test
    void testExecute_SingleSample() {
        // Given: 只有1个样本
        List<Long> sampleListIds = Arrays.asList(101L);
        context.setSampleListIds(sampleListIds);

        List<MemberSourceEntity> memberSourceList = createMemberSourceList(1);
        when(sourceRelationProcessor.processMemberSources(sampleListIds, face))
                .thenReturn(memberSourceList);

        // When
        StageResult<FaceMatchingContext> result = stage.execute(context);

        // Then
        assertTrue(result.isSuccess());
        assertTrue(result.getMessage().contains("构建了1个源文件关联"));
    }

    @Test
    void testExecute_ManySamples() {
        // Given: 大量样本
        List<Long> sampleListIds = Arrays.asList(101L, 102L, 103L, 104L, 105L, 106L, 107L, 108L, 109L, 110L);
        context.setSampleListIds(sampleListIds);

        List<MemberSourceEntity> memberSourceList = createMemberSourceList(10);
        when(sourceRelationProcessor.processMemberSources(sampleListIds, face))
                .thenReturn(memberSourceList);

        // When
        StageResult<FaceMatchingContext> result = stage.execute(context);

        // Then
        assertTrue(result.isSuccess());
        assertTrue(result.getMessage().contains("构建了10个源文件关联"));
        assertEquals(10, context.getMemberSourceList().size());
    }

    @Test
    void testExecute_SampleListIdsDifferentFromResult() {
        // Given: sampleListIds与processMemberSources返回的数量不同(部分无效)
        List<Long> sampleListIds = Arrays.asList(101L, 102L, 103L, 104L, 105L);
        context.setSampleListIds(sampleListIds);

        List<MemberSourceEntity> memberSourceList = createMemberSourceList(3); // 只有3个有效
        when(sourceRelationProcessor.processMemberSources(sampleListIds, face))
                .thenReturn(memberSourceList);

        // When
        StageResult<FaceMatchingContext> result = stage.execute(context);

        // Then
        assertTrue(result.isSuccess());
        assertTrue(result.getMessage().contains("构建了3个源文件关联"));
        assertEquals(3, context.getMemberSourceList().size());
    }

    private List<MemberSourceEntity> createMemberSourceList(int count) {
        List<MemberSourceEntity> list = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            MemberSourceEntity entity = new MemberSourceEntity();
            entity.setMemberId(100L);
            entity.setSourceId((long) (i + 1));
            list.add(entity);
        }
        return list;
    }
}
