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

import com.ycwl.basic.exception.BaseException;
import com.ycwl.basic.face.pipeline.core.FaceMatchingContext;
import com.ycwl.basic.pipeline.core.StageResult;
import com.ycwl.basic.facebody.adapter.IFaceBodyAdapter;
import com.ycwl.basic.model.pc.face.entity.FaceEntity;
import com.ycwl.basic.model.task.resp.SearchFaceRespVo;
import com.ycwl.basic.service.task.TaskFaceService;
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.Arrays;

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

/**
 * FaceRecognitionStage 单元测试
 */
@ExtendWith(MockitoExtension.class)
class FaceRecognitionStageTest {

    @Mock
    private TaskFaceService taskFaceService;

    @Mock
    private IFaceBodyAdapter faceBodyAdapter;

    @InjectMocks
    private FaceRecognitionStage stage;

    private FaceMatchingContext context;
    private FaceEntity face;

    @BeforeEach
    void setUp() {
        context = FaceMatchingContext.forAutoMatching(1L, true);
        face = new FaceEntity();
        face.setId(1L);
        face.setScenicId(10L);
        face.setFaceUrl("http://example.com/face.jpg");
        context.setFace(face);
        context.setFaceBodyAdapter(faceBodyAdapter);
    }

    @Test
    void testExecute_Success() throws Exception {
        // Given
        SearchFaceRespVo searchResult = new SearchFaceRespVo();
        searchResult.setScore(0.85f);
        searchResult.setSampleListIds(Arrays.asList(101L, 102L, 103L));

        when(taskFaceService.searchFace(
                eq(faceBodyAdapter),
                eq("10"),
                eq("http://example.com/face.jpg"),
                eq("人脸识别")
        )).thenReturn(searchResult);

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

        // Then
        assertTrue(result.isSuccess());
        assertEquals(searchResult, context.getSearchResult());
        assertEquals(0.85f, context.getSearchResult().getScore(), 0.0001);
        assertEquals(3, context.getSearchResult().getSampleListIds().size());
        verify(taskFaceService, times(1)).searchFace(any(), anyString(), anyString(), anyString());
    }

    @Test
    void testExecute_SearchResultNull_Failed() throws Exception {
        // Given
        when(taskFaceService.searchFace(any(), anyString(), anyString(), anyString()))
                .thenReturn(null);

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

        // Then
        assertTrue(result.isFailed());
        assertTrue(result.getMessage().contains("人脸识别失败"));
        assertNull(context.getSearchResult());
    }

    @Test
    void testExecute_SearchResultEmptyList() throws Exception {
        // Given
        SearchFaceRespVo searchResult = new SearchFaceRespVo();
        searchResult.setScore(0.45f); // 低分
        searchResult.setSampleListIds(Arrays.asList()); // 空列表

        when(taskFaceService.searchFace(any(), anyString(), anyString(), anyString()))
                .thenReturn(searchResult);

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

        // Then
        assertTrue(result.isSuccess()); // 即使没有匹配也成功
        assertEquals(searchResult, context.getSearchResult());
        assertEquals(0, context.getSearchResult().getSampleListIds().size());
    }

    @Test
    void testExecute_BaseException_Throw() throws Exception {
        // Given
        BaseException baseException = new BaseException("识别服务异常");
        when(taskFaceService.searchFace(any(), anyString(), anyString(), anyString()))
                .thenThrow(baseException);

        // When & Then
        assertThrows(BaseException.class, () -> {
            stage.execute(context);
        });
    }

    @Test
    void testExecute_GenericException_Failed() throws Exception {
        // Given
        when(taskFaceService.searchFace(any(), anyString(), anyString(), anyString()))
                .thenThrow(new RuntimeException("Network error"));

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

        // Then
        assertTrue(result.isFailed());
        assertTrue(result.getMessage().contains("人脸识别失败"));
        assertNotNull(result.getException());
    }

    @Test
    void testExecute_NullFaceUrl() throws Exception {
        // Given
        face.setFaceUrl(null);

        when(taskFaceService.searchFace(any(), anyString(), isNull(), anyString()))
                .thenThrow(new IllegalArgumentException("Face URL is null"));

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

        // Then
        assertTrue(result.isFailed());
    }

    @Test
    void testExecute_HighScoreResult() throws Exception {
        // Given: 高分匹配
        SearchFaceRespVo searchResult = new SearchFaceRespVo();
        searchResult.setScore(0.95f);
        searchResult.setSampleListIds(Arrays.asList(101L));

        when(taskFaceService.searchFace(any(), anyString(), anyString(), anyString()))
                .thenReturn(searchResult);

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

        // Then
        assertTrue(result.isSuccess());
        assertEquals(0.95f, context.getSearchResult().getScore(), 0.0001);
    }

    @Test
    void testExecute_MultipleMatches() throws Exception {
        // Given: 多个匹配结果
        SearchFaceRespVo searchResult = new SearchFaceRespVo();
        searchResult.setScore(0.78f);
        searchResult.setSampleListIds(Arrays.asList(101L, 102L, 103L, 104L, 105L));

        when(taskFaceService.searchFace(any(), anyString(), anyString(), anyString()))
                .thenReturn(searchResult);

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

        // Then
        assertTrue(result.isSuccess());
        assertEquals(5, context.getSearchResult().getSampleListIds().size());
        assertTrue(result.getMessage().contains("匹配数=5"));
    }
}
