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

import com.ycwl.basic.face.pipeline.core.FaceMatchingContext;
import com.ycwl.basic.face.pipeline.enums.FaceMatchingScene;
import com.ycwl.basic.face.pipeline.factory.FaceMatchingPipelineFactory;
import com.ycwl.basic.face.pipeline.stages.BuildSourceRelationStage;
import com.ycwl.basic.face.pipeline.stages.CreateTaskStage;
import com.ycwl.basic.face.pipeline.stages.CustomFaceSearchStage;
import com.ycwl.basic.face.pipeline.stages.DeleteOldRelationsStage;
import com.ycwl.basic.face.pipeline.stages.FaceRecognitionStage;
import com.ycwl.basic.face.pipeline.stages.FaceRecoveryStage;
import com.ycwl.basic.face.pipeline.stages.FilterByDevicePhotoLimitStage;
import com.ycwl.basic.face.pipeline.stages.FilterByTimeRangeStage;
import com.ycwl.basic.face.pipeline.stages.GeneratePuzzleStage;
import com.ycwl.basic.face.pipeline.stages.HandleVideoRecreationStage;
import com.ycwl.basic.face.pipeline.stages.LoadFaceSamplesStage;
import com.ycwl.basic.face.pipeline.stages.LoadMatchedSamplesStage;
import com.ycwl.basic.face.pipeline.stages.PersistRelationsStage;
import com.ycwl.basic.face.pipeline.stages.PrepareContextStage;
import com.ycwl.basic.face.pipeline.stages.ProcessBuyStatusStage;
import com.ycwl.basic.face.pipeline.stages.ProcessFreeSourceStage;
import com.ycwl.basic.face.pipeline.stages.RecordCustomMatchMetricsStage;
import com.ycwl.basic.face.pipeline.stages.RecordMetricsStage;
import com.ycwl.basic.face.pipeline.stages.SetTaskStatusStage;
import com.ycwl.basic.face.pipeline.stages.UpdateFaceResultStage;
import com.ycwl.basic.pipeline.core.Pipeline;
import com.ycwl.basic.service.pc.helper.ScenicConfigFacade;
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.*;

/**
 * Pipeline集成测试
 * 测试Pipeline的完整流程和Stage协作
 */
@ExtendWith(MockitoExtension.class)
class FaceMatchingPipelineIntegrationTest {

    @InjectMocks
    private FaceMatchingPipelineFactory pipelineFactory;

    @Mock
    private PrepareContextStage prepareContextStage;
    @Mock
    private RecordMetricsStage recordMetricsStage;
    @Mock
    private FaceRecognitionStage faceRecognitionStage;
    @Mock
    private FaceRecoveryStage faceRecoveryStage;
    @Mock
    private UpdateFaceResultStage updateFaceResultStage;
    @Mock
    private BuildSourceRelationStage buildSourceRelationStage;
    @Mock
    private ProcessFreeSourceStage processFreeSourceStage;
    @Mock
    private ProcessBuyStatusStage processBuyStatusStage;
    @Mock
    private HandleVideoRecreationStage handleVideoRecreationStage;
    @Mock
    private PersistRelationsStage persistRelationsStage;
    @Mock
    private CreateTaskStage createTaskStage;
    @Mock
    private SetTaskStatusStage setTaskStatusStage;
    @Mock
    private GeneratePuzzleStage generatePuzzleStage;
    @Mock
    private RecordCustomMatchMetricsStage recordCustomMatchMetricsStage;
    @Mock
    private LoadFaceSamplesStage loadFaceSamplesStage;
    @Mock
    private CustomFaceSearchStage customFaceSearchStage;
    @Mock
    private LoadMatchedSamplesStage loadMatchedSamplesStage;
    @Mock
    private FilterByTimeRangeStage filterByTimeRangeStage;
    @Mock
    private FilterByDevicePhotoLimitStage filterByDevicePhotoLimitStage;
    @Mock
    private DeleteOldRelationsStage deleteOldRelationsStage;
    @Mock
    private ScenicConfigFacade scenicConfigFacade;

    /**
     * 测试Pipeline工厂能够成功创建Pipeline
     */
    @Test
    void testCreatePipelines() {
        // When: 创建各种场景的Pipeline
        Pipeline<FaceMatchingContext> autoMatchingNew = pipelineFactory.createAutoMatchingPipeline(true);
        Pipeline<FaceMatchingContext> autoMatchingOld = pipelineFactory.createAutoMatchingPipeline(false);
        Pipeline<FaceMatchingContext> customMatching = pipelineFactory.createCustomMatchingPipeline();
        Pipeline<FaceMatchingContext> recognitionOnly = pipelineFactory.createRecognitionOnlyPipeline();

        // Then: 验证Pipeline创建成功
        assertNotNull(autoMatchingNew);
        assertNotNull(autoMatchingOld);
        assertNotNull(customMatching);
        assertNotNull(recognitionOnly);

        // 验证Stage数量符合预期
        assertEquals(13, autoMatchingNew.getStageCount());
        assertEquals(12, autoMatchingOld.getStageCount());
        assertEquals(15, customMatching.getStageCount());
        assertEquals(3, recognitionOnly.getStageCount());
    }

    /**
     * 测试通过场景和isNew参数创建Pipeline
     */
    @Test
    void testCreatePipelineByScene() {
        // When
        Pipeline<FaceMatchingContext> autoNew = pipelineFactory.createPipeline(FaceMatchingScene.AUTO_MATCHING, true);
        Pipeline<FaceMatchingContext> autoOld = pipelineFactory.createPipeline(FaceMatchingScene.AUTO_MATCHING, false);
        Pipeline<FaceMatchingContext> custom = pipelineFactory.createPipeline(FaceMatchingScene.CUSTOM_MATCHING, false);
        Pipeline<FaceMatchingContext> recognition = pipelineFactory.createPipeline(FaceMatchingScene.RECOGNITION_ONLY, false);

        // Then
        assertNotNull(autoNew);
        assertNotNull(autoOld);
        assertNotNull(custom);
        assertNotNull(recognition);
    }

    /**
     * 测试通过Context创建Pipeline
     */
    @Test
    void testCreatePipelineByContext() {
        // Given
        FaceMatchingContext autoContext = FaceMatchingContext.forAutoMatching(1L, true);
        FaceMatchingContext customContext = FaceMatchingContext.forCustomMatching(2L, Arrays.asList(101L, 102L));
        FaceMatchingContext recognitionContext = FaceMatchingContext.forRecognitionOnly(3L);

        // When
        Pipeline<FaceMatchingContext> autoPipeline = pipelineFactory.createPipeline(autoContext);
        Pipeline<FaceMatchingContext> customPipeline = pipelineFactory.createPipeline(customContext);
        Pipeline<FaceMatchingContext> recognitionPipeline = pipelineFactory.createPipeline(recognitionContext);

        // Then
        assertNotNull(autoPipeline);
        assertNotNull(customPipeline);
        assertNotNull(recognitionPipeline);
    }

    /**
     * 测试Pipeline名称
     */
    @Test
    void testPipelineNames() {
        // When
        Pipeline<FaceMatchingContext> autoNew = pipelineFactory.createAutoMatchingPipeline(true);
        Pipeline<FaceMatchingContext> autoOld = pipelineFactory.createAutoMatchingPipeline(false);
        Pipeline<FaceMatchingContext> custom = pipelineFactory.createCustomMatchingPipeline();
        Pipeline<FaceMatchingContext> recognition = pipelineFactory.createRecognitionOnlyPipeline();

        // Then
        assertTrue(autoNew.getName().contains("AutoMatching"));
        assertTrue(autoNew.getName().contains("New"));
        assertTrue(autoOld.getName().contains("AutoMatching"));
        assertTrue(autoOld.getName().contains("Old"));
        assertTrue(custom.getName().contains("CustomMatching"));
        assertTrue(recognition.getName().contains("RecognitionOnly"));
    }

    /**
     * 测试Context构建
     */
    @Test
    void testContextCreation() {
        // When: 使用不同的工厂方法创建Context
        FaceMatchingContext autoContext = FaceMatchingContext.forAutoMatching(100L, true);
        FaceMatchingContext customContext = FaceMatchingContext.forCustomMatching(200L, Arrays.asList(1L, 2L, 3L));
        FaceMatchingContext recognitionContext = FaceMatchingContext.forRecognitionOnly(300L);

        // Then: 验证Context属性
        assertEquals(100L, autoContext.getFaceId());
        assertTrue(autoContext.isNew());
        assertEquals(FaceMatchingScene.AUTO_MATCHING, autoContext.getScene());

        assertEquals(200L, customContext.getFaceId());
        assertFalse(customContext.isNew());
        assertEquals(FaceMatchingScene.CUSTOM_MATCHING, customContext.getScene());
        assertEquals(3, customContext.getFaceSampleIds().size());

        assertEquals(300L, recognitionContext.getFaceId());
        assertFalse(recognitionContext.isNew());
        assertEquals(FaceMatchingScene.RECOGNITION_ONLY, recognitionContext.getScene());
    }

    /**
     * 测试Context的Stage开关配置
     */
    @Test
    void testContextStageConfiguration() {
        // Given
        FaceMatchingContext context = FaceMatchingContext.forAutoMatching(1L, true);

        // When: 配置Stage开关
        context.enableStage("stage1");
        context.disableStage("stage2");
        context.setStageState("stage3", true);

        // Then
        assertTrue(context.isStageEnabled("stage1"));
        assertFalse(context.isStageEnabled("stage2"));
        assertTrue(context.isStageEnabled("stage3"));
        assertFalse(context.isStageEnabled("non_exist_stage")); // 默认false
    }

    /**
     * 测试Context Builder
     */
    @Test
    void testContextBuilder() {
        // When
        FaceMatchingContext context = FaceMatchingContext.builder()
                .faceId(999L)
                .isNew(true)
                .scene(FaceMatchingScene.AUTO_MATCHING)
                .build();

        // Then
        assertEquals(999L, context.getFaceId());
        assertTrue(context.isNew());
        assertEquals(FaceMatchingScene.AUTO_MATCHING, context.getScene());
    }

    /**
     * 测试Builder参数校验
     */
    @Test
    void testContextBuilderValidation() {
        // When & Then: faceId为null应该抛异常
        assertThrows(IllegalArgumentException.class, () -> {
            FaceMatchingContext.builder()
                    .scene(FaceMatchingScene.AUTO_MATCHING)
                    .build();
        });

        // When & Then: scene为null应该抛异常
        assertThrows(IllegalArgumentException.class, () -> {
            FaceMatchingContext.builder()
                    .faceId(1L)
                    .build();
        });

        // When & Then: CUSTOM_MATCHING场景必须提供faceSampleIds
        assertThrows(IllegalArgumentException.class, () -> {
            FaceMatchingContext.builder()
                    .faceId(1L)
                    .scene(FaceMatchingScene.CUSTOM_MATCHING)
                    .build();
        });
    }
}
