package com.ycwl.basic.image.pipeline.core;

import com.ycwl.basic.pipeline.core.AbstractPipelineStage;
import com.ycwl.basic.pipeline.core.Pipeline;
import com.ycwl.basic.pipeline.core.PipelineBuilder;
import com.ycwl.basic.pipeline.core.StageResult;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

/**
 * Pipeline 单元测试
 */
class PipelineTest {

    @Test
    void testPipelineExecution_AllSuccess() {
        Pipeline<PhotoProcessContext> pipeline = new PipelineBuilder<PhotoProcessContext>("TestPipeline")
                .addStage(new MockStage("stage1", StageResult.success("Stage1完成")))
                .addStage(new MockStage("stage2", StageResult.success("Stage2完成")))
                .addStage(new MockStage("stage3", StageResult.success("Stage3完成")))
                .build();

        PhotoProcessContext context = createTestContext();

        boolean success = pipeline.execute(context);

        assertTrue(success);
    }

    @Test
    void testPipelineExecution_WithSkippedStage() {
        Pipeline<PhotoProcessContext> pipeline = new PipelineBuilder<PhotoProcessContext>("TestPipeline")
                .addStage(new MockStage("stage1", StageResult.success()))
                .addStage(new ConditionalStage("stage2", false))
                .addStage(new MockStage("stage3", StageResult.success()))
                .build();

        PhotoProcessContext context = createTestContext();

        boolean success = pipeline.execute(context);

        assertTrue(success);
    }

    @Test
    void testPipelineExecution_WithDegradedStage() {
        Pipeline<PhotoProcessContext> pipeline = new PipelineBuilder<PhotoProcessContext>("TestPipeline")
                .addStage(new MockStage("stage1", StageResult.success()))
                .addStage(new MockStage("stage2", StageResult.degraded("降级执行")))
                .addStage(new MockStage("stage3", StageResult.success()))
                .build();

        PhotoProcessContext context = createTestContext();

        boolean success = pipeline.execute(context);

        assertTrue(success);
    }

    @Test
    void testPipelineExecution_WithFailedStage() {
        Pipeline<PhotoProcessContext> pipeline = new PipelineBuilder<PhotoProcessContext>("TestPipeline")
                .addStage(new MockStage("stage1", StageResult.success()))
                .addStage(new MockStage("stage2", StageResult.failed("执行失败")))
                .addStage(new MockStage("stage3", StageResult.success()))
                .build();

        PhotoProcessContext context = createTestContext();

        boolean success = pipeline.execute(context);

        assertFalse(success);
    }

    @Test
    void testPipelineExecution_WithDynamicStageAddition() {
        MockStage dynamicStage = new MockStage("dynamic", StageResult.success("动态Stage完成"));

        Pipeline<PhotoProcessContext> pipeline = new PipelineBuilder<PhotoProcessContext>("TestPipeline")
                .addStage(new MockStage("stage1", StageResult.success()))
                .addStage(new MockStage("stage2", StageResult.successWithNext("添加动态Stage", dynamicStage)))
                .addStage(new MockStage("stage3", StageResult.success()))
                .build();

        PhotoProcessContext context = createTestContext();

        boolean success = pipeline.execute(context);

        assertTrue(success);
        assertEquals(4, pipeline.getStageCount()); // 原3个 + 动态添加1个
    }

    @Test
    void testPipelineName() {
        Pipeline<PhotoProcessContext> pipeline = new PipelineBuilder<PhotoProcessContext>("CustomPipeline")
                .addStage(new MockStage("stage1", StageResult.success()))
                .build();

        assertEquals("CustomPipeline", pipeline.getName());
    }

    @Test
    void testGetStageCount() {
        Pipeline<PhotoProcessContext> pipeline = new PipelineBuilder<PhotoProcessContext>()
                .addStage(new MockStage("stage1", StageResult.success()))
                .addStage(new MockStage("stage2", StageResult.success()))
                .addStage(new MockStage("stage3", StageResult.success()))
                .build();

        assertEquals(3, pipeline.getStageCount());
    }

    @Test
    void testGetStageNames() {
        Pipeline<PhotoProcessContext> pipeline = new PipelineBuilder<PhotoProcessContext>()
                .addStage(new MockStage("stage1", StageResult.success()))
                .addStage(new MockStage("stage2", StageResult.success()))
                .build();

        var names = pipeline.getStageNames();

        assertEquals(2, names.size());
        assertTrue(names.contains("MockStage-stage1"));
        assertTrue(names.contains("MockStage-stage2"));
    }

    @Test
    void testPipelineFailureStillCleansTempFiles() {
        Pipeline<PhotoProcessContext> pipeline = new PipelineBuilder<PhotoProcessContext>("CleanupGuarantee")
                .addStage(new TempFileFailStage())
                .build();

        PhotoProcessContext context = createTestContext();

        boolean success = pipeline.execute(context);

        assertFalse(success);
        assertEquals(0, context.getTempFileManager().getTempFileCount());
    }

    /**
     * 创建测试用的 Context
     */
    private PhotoProcessContext createTestContext() {
        return PhotoProcessContext.builder()
                .processId("test-pipeline")
                .originalUrl("https://example.com/test.jpg")
                .scenicId(123L)
                .build();
    }

    /**
     * Mock Stage for testing
     */
    private static class MockStage extends AbstractPipelineStage<PhotoProcessContext> {
        private final String id;
        private final StageResult<PhotoProcessContext> result;

        MockStage(String id, StageResult<PhotoProcessContext> result) {
            this.id = id;
            this.result = result;
        }

        @Override
        public String getName() {
            return "MockStage-" + id;
        }

        @Override
        protected StageResult<PhotoProcessContext> doExecute(PhotoProcessContext context) {
            return result;
        }
    }

    /**
     * Conditional Stage for testing
     */
    private static class ConditionalStage extends AbstractPipelineStage<PhotoProcessContext> {
        private final String id;
        private final boolean shouldExecute;

        ConditionalStage(String id, boolean shouldExecute) {
            this.id = id;
            this.shouldExecute = shouldExecute;
        }

        @Override
        public String getName() {
            return "ConditionalStage-" + id;
        }

        @Override
        protected boolean shouldExecuteByBusinessLogic(PhotoProcessContext context) {
            return shouldExecute;
        }

        @Override
        protected StageResult<PhotoProcessContext> doExecute(PhotoProcessContext context) {
            return StageResult.success();
        }
    }

    private static class TempFileFailStage extends AbstractPipelineStage<PhotoProcessContext> {

        @Override
        public String getName() {
            return "TempFileFailStage";
        }

        @Override
        protected StageResult<PhotoProcessContext> doExecute(PhotoProcessContext context) {
            context.getTempFileManager().createTempFile("fail", ".tmp");
            return StageResult.failed("force failure");
        }
    }
}
