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

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

import java.util.List;

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

/**
 * StageResult 单元测试
 */
class StageResultTest {

    @Test
    void testSuccess() {
        StageResult<PhotoProcessContext> result = StageResult.success();

        assertEquals(StageResult.Status.SUCCESS, result.getStatus());
        assertTrue(result.isSuccess());
        assertFalse(result.isFailed());
        assertFalse(result.isSkipped());
        assertFalse(result.isDegraded());
        assertTrue(result.canContinue());
    }

    @Test
    void testSuccessWithMessage() {
        StageResult<PhotoProcessContext> result = StageResult.success("处理完成");

        assertTrue(result.isSuccess());
        assertEquals("处理完成", result.getMessage());
    }

    @Test
    void testSuccessWithNextStages() {
        MockStage nextStage1 = new MockStage("next1");
        MockStage nextStage2 = new MockStage("next2");

        StageResult<PhotoProcessContext> result = StageResult.successWithNext("添加后续Stage", nextStage1, nextStage2);

        assertTrue(result.isSuccess());
        assertEquals("添加后续Stage", result.getMessage());
        assertEquals(2, result.getNextStages().size());
        assertEquals("MockStage-next1", result.getNextStages().get(0).getName());
        assertEquals("MockStage-next2", result.getNextStages().get(1).getName());
    }

    @Test
    void testSuccessWithNextStagesList() {
        List<PipelineStage<PhotoProcessContext>> stages = List.of(
                new MockStage("next1"),
                new MockStage("next2")
        );

        StageResult<PhotoProcessContext> result = StageResult.successWithNext("添加列表", stages);

        assertEquals(2, result.getNextStages().size());
    }

    @Test
    void testSkipped() {
        StageResult<PhotoProcessContext> result = StageResult.skipped();

        assertEquals(StageResult.Status.SKIPPED, result.getStatus());
        assertTrue(result.isSkipped());
        assertTrue(result.canContinue());
        assertEquals("条件不满足,跳过执行", result.getMessage());
    }

    @Test
    void testSkippedWithReason() {
        StageResult<PhotoProcessContext> result = StageResult.skipped("图片类型不匹配");

        assertTrue(result.isSkipped());
        assertEquals("图片类型不匹配", result.getMessage());
    }

    @Test
    void testFailed() {
        StageResult<PhotoProcessContext> result = StageResult.failed("下载失败");

        assertEquals(StageResult.Status.FAILED, result.getStatus());
        assertTrue(result.isFailed());
        assertFalse(result.canContinue());
        assertEquals("下载失败", result.getMessage());
    }

    @Test
    void testFailedWithException() {
        Exception exception = new RuntimeException("网络错误");
        StageResult<PhotoProcessContext> result = StageResult.failed("下载失败", exception);

        assertTrue(result.isFailed());
        assertEquals("下载失败", result.getMessage());
        assertEquals(exception, result.getException());
    }

    @Test
    void testDegraded() {
        StageResult<PhotoProcessContext> result = StageResult.degraded("使用备用方案");

        assertEquals(StageResult.Status.DEGRADED, result.getStatus());
        assertTrue(result.isDegraded());
        assertTrue(result.canContinue());
        assertEquals("使用备用方案", result.getMessage());
    }

    @Test
    void testCanContinue_Success() {
        assertTrue(StageResult.success().canContinue());
    }

    @Test
    void testCanContinue_Skipped() {
        assertTrue(StageResult.skipped().canContinue());
    }

    @Test
    void testCanContinue_Degraded() {
        assertTrue(StageResult.degraded("降级").canContinue());
    }

    @Test
    void testCanContinue_Failed() {
        assertFalse(StageResult.failed("失败").canContinue());
    }

    @Test
    void testNextStagesImmutable() {
        MockStage stage1 = new MockStage("stage1");
        StageResult<PhotoProcessContext> result = StageResult.successWithNext("test", stage1);

        List<PipelineStage<PhotoProcessContext>> nextStages = result.getNextStages();

        assertThrows(UnsupportedOperationException.class, () -> {
            nextStages.add(new MockStage("stage2"));
        });
    }

    /**
     * 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();
        }
    }
}
