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.facebody.adapter.IFaceBodyAdapter;
import com.ycwl.basic.integration.common.manager.ScenicConfigManager;
import com.ycwl.basic.model.pc.face.entity.FaceEntity;
import com.ycwl.basic.model.task.resp.SearchFaceRespVo;
import com.ycwl.basic.service.pc.processor.FaceRecoveryStrategy;
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 static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.*;

/**
 * FaceRecoveryStage 单元测试
 */
@ExtendWith(MockitoExtension.class)
class FaceRecoveryStageTest {

    @Mock
    private FaceRecoveryStrategy faceRecoveryStrategy;

    @InjectMocks
    private FaceRecoveryStage stage;

    private FaceMatchingContext context;
    private FaceEntity face;
    private ScenicConfigManager scenicConfig;
    private IFaceBodyAdapter faceBodyAdapter;

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

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

        scenicConfig = mock(ScenicConfigManager.class);
        faceBodyAdapter = mock(IFaceBodyAdapter.class);

        context.setFace(face);
        context.setScenicConfig(scenicConfig);
        context.setFaceBodyAdapter(faceBodyAdapter);
    }

    @Test
    void testExecute_SearchResultNull_Skipped() {
        // Given: searchResult为null
        context.setSearchResult(null);

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

        // Then
        assertTrue(result.isSkipped());
        verify(faceRecoveryStrategy, never()).executeFaceRecoveryLogic(any(), any(), any(), anyLong());
    }

    @Test
    void testExecute_NoRecoveryNeeded_Success() {
        // Given: 不需要补救,返回原searchResult
        SearchFaceRespVo searchResult = new SearchFaceRespVo();
        searchResult.setScore(0.85f);
        context.setSearchResult(searchResult);

        when(faceRecoveryStrategy.executeFaceRecoveryLogic(
                searchResult, scenicConfig, faceBodyAdapter, 10L))
                .thenReturn(searchResult); // 返回同一个对象

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

        // Then
        assertTrue(result.isSuccess());
        assertTrue(result.getMessage().contains("无需补救"));
        assertEquals(searchResult, context.getSearchResult());
        verify(faceRecoveryStrategy, times(1))
                .executeFaceRecoveryLogic(searchResult, scenicConfig, faceBodyAdapter, 10L);
    }

    @Test
    void testExecute_RecoveryTriggered_Degraded() {
        // Given: 触发补救,返回新的searchResult
        SearchFaceRespVo originalResult = new SearchFaceRespVo();
        originalResult.setScore(0.50f);
        context.setSearchResult(originalResult);

        SearchFaceRespVo recoveredResult = new SearchFaceRespVo();
        recoveredResult.setScore(0.85f);

        when(faceRecoveryStrategy.executeFaceRecoveryLogic(
                originalResult, scenicConfig, faceBodyAdapter, 10L))
                .thenReturn(recoveredResult); // 返回新对象

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

        // Then
        assertTrue(result.isDegraded());
        assertTrue(result.getMessage().contains("触发补救逻辑，重新搜索"));
        assertEquals(recoveredResult, context.getSearchResult());
        assertNotEquals(originalResult, context.getSearchResult());
    }

    @Test
    void testExecute_RecoveryStrategyFailed_Degraded() {
        // Given: 补救策略执行失败
        SearchFaceRespVo searchResult = new SearchFaceRespVo();
        searchResult.setScore(0.50f);
        context.setSearchResult(searchResult);

        when(faceRecoveryStrategy.executeFaceRecoveryLogic(
                searchResult, scenicConfig, faceBodyAdapter, 10L))
                .thenThrow(new RuntimeException("Recovery strategy error"));

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

        // Then
        assertTrue(result.isDegraded());
        assertTrue(result.getMessage().contains("补救逻辑执行失败"));
        verify(faceRecoveryStrategy, times(1))
                .executeFaceRecoveryLogic(searchResult, scenicConfig, faceBodyAdapter, 10L);
    }

    @Test
    void testExecute_DifferentScenicId() {
        // Given: 不同的景区ID
        face.setScenicId(888L);

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

        when(faceRecoveryStrategy.executeFaceRecoveryLogic(
                searchResult, scenicConfig, faceBodyAdapter, 888L))
                .thenReturn(searchResult);

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

        // Then
        assertTrue(result.isSuccess());
        verify(faceRecoveryStrategy, times(1))
                .executeFaceRecoveryLogic(searchResult, scenicConfig, faceBodyAdapter, 888L);
    }

    @Test
    void testExecute_NullFaceBodyAdapter() {
        // Given: faceBodyAdapter为null
        context.setFaceBodyAdapter(null);

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

        when(faceRecoveryStrategy.executeFaceRecoveryLogic(
                searchResult, scenicConfig, null, 10L))
                .thenReturn(searchResult);

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

        // Then
        assertTrue(result.isSuccess());
        verify(faceRecoveryStrategy, times(1))
                .executeFaceRecoveryLogic(searchResult, scenicConfig, null, 10L);
    }

    @Test
    void testExecute_NullScenicConfig() {
        // Given: scenicConfig为null
        context.setScenicConfig(null);

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

        when(faceRecoveryStrategy.executeFaceRecoveryLogic(
                searchResult, null, faceBodyAdapter, 10L))
                .thenReturn(searchResult);

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

        // Then
        assertTrue(result.isSuccess());
        verify(faceRecoveryStrategy, times(1))
                .executeFaceRecoveryLogic(searchResult, null, faceBodyAdapter, 10L);
    }

    @Test
    void testExecute_NullPointerException_Degraded() {
        // Given: 空指针异常
        SearchFaceRespVo searchResult = new SearchFaceRespVo();
        context.setSearchResult(searchResult);

        when(faceRecoveryStrategy.executeFaceRecoveryLogic(
                searchResult, scenicConfig, faceBodyAdapter, 10L))
                .thenThrow(new NullPointerException("Null strategy"));

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

        // Then
        assertTrue(result.isDegraded());
        assertTrue(result.getMessage().contains("补救逻辑执行失败"));
    }
}
