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.*;

/**
 * PipelineBuilder 单元测试
 */
class PipelineBuilderTest {

    @Test
    void testBuildEmptyPipeline_ShouldThrowException() {
        PipelineBuilder<PhotoProcessContext> builder = new PipelineBuilder<>();

        Exception exception = assertThrows(IllegalStateException.class, builder::build);

        assertEquals("Pipeline 至少需要一个 Stage", exception.getMessage());
    }

    @Test
    void testBuildWithDefaultName() {
        PipelineBuilder<PhotoProcessContext> builder = new PipelineBuilder<>();
        builder.addStage(new MockStage("stage1"));

        Pipeline<PhotoProcessContext> pipeline = builder.build();

        assertEquals("DefaultPipeline", pipeline.getName());
        assertEquals(1, pipeline.getStageCount());
    }

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

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

    @Test
    void testAddStage() {
        PipelineBuilder<PhotoProcessContext> builder = new PipelineBuilder<>();
        builder.addStage(new MockStage("stage1"));
        builder.addStage(new MockStage("stage2"));

        Pipeline<PhotoProcessContext> pipeline = builder.build();

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

    @Test
    void testAddStageWithNull_ShouldIgnore() {
        PipelineBuilder<PhotoProcessContext> builder = new PipelineBuilder<>();
        builder.addStage(new MockStage("stage1"));
        builder.addStage(null);
        builder.addStage(new MockStage("stage2"));

        Pipeline<PhotoProcessContext> pipeline = builder.build();

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

    @Test
    void testAddStageIf_WhenTrue() {
        PipelineBuilder<PhotoProcessContext> builder = new PipelineBuilder<>();
        builder.addStageIf(true, new MockStage("stage1"));

        Pipeline<PhotoProcessContext> pipeline = builder.build();

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

    @Test
    void testAddStageIf_WhenFalse() {
        PipelineBuilder<PhotoProcessContext> builder = new PipelineBuilder<>();
        builder.addStage(new MockStage("required"));
        builder.addStageIf(false, new MockStage("optional"));

        Pipeline<PhotoProcessContext> pipeline = builder.build();

        assertEquals(1, pipeline.getStageCount());
        assertTrue(pipeline.getStageNames().contains("MockStage-required"));
        assertFalse(pipeline.getStageNames().contains("MockStage-optional"));
    }

    @Test
    void testFluentAPI() {
        Pipeline<PhotoProcessContext> pipeline = new PipelineBuilder<PhotoProcessContext>()
                .name("FluentPipeline")
                .addStage(new MockStage("stage1"))
                .addStage(new MockStage("stage2"))
                .addStageIf(true, new MockStage("stage3"))
                .build();

        assertEquals("FluentPipeline", pipeline.getName());
        assertEquals(3, pipeline.getStageCount());
    }

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

        MockStage(String id) {
            this.id = id;
        }

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

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