package com.ycwl.basic.pipeline.core;

import lombok.Getter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * Stage 执行结果对象。
 */
@Getter
public class StageResult<C extends PipelineContext> {

    public enum Status {
        SUCCESS,
        SKIPPED,
        FAILED,
        DEGRADED
    }

    private final Status status;
    private final String message;
    private final Throwable exception;
    private final List<PipelineStage<C>> nextStages;

    private StageResult(Status status, String message, Throwable exception, List<PipelineStage<C>> nextStages) {
        this.status = status;
        this.message = message;
        this.exception = exception;
        this.nextStages = nextStages != null
            ? Collections.unmodifiableList(new ArrayList<>(nextStages))
            : Collections.emptyList();
    }

    public static <C extends PipelineContext> StageResult<C> success() {
        return new StageResult<>(Status.SUCCESS, null, null, null);
    }

    public static <C extends PipelineContext> StageResult<C> success(String message) {
        return new StageResult<>(Status.SUCCESS, message, null, null);
    }

    @SafeVarargs
    public static <C extends PipelineContext> StageResult<C> successWithNext(String message, PipelineStage<C>... stages) {
        return new StageResult<>(Status.SUCCESS, message, null, Arrays.asList(stages));
    }

    public static <C extends PipelineContext> StageResult<C> successWithNext(String message, List<PipelineStage<C>> stages) {
        return new StageResult<>(Status.SUCCESS, message, null, stages);
    }

    public static <C extends PipelineContext> StageResult<C> skipped() {
        return new StageResult<>(Status.SKIPPED, "条件不满足,跳过执行", null, null);
    }

    public static <C extends PipelineContext> StageResult<C> skipped(String reason) {
        return new StageResult<>(Status.SKIPPED, reason, null, null);
    }

    public static <C extends PipelineContext> StageResult<C> failed(String message) {
        return new StageResult<>(Status.FAILED, message, null, null);
    }

    public static <C extends PipelineContext> StageResult<C> failed(String message, Throwable exception) {
        return new StageResult<>(Status.FAILED, message, exception, null);
    }

    public static <C extends PipelineContext> StageResult<C> degraded(String message) {
        return new StageResult<>(Status.DEGRADED, message, null, null);
    }

    public boolean isSuccess() {
        return status == Status.SUCCESS;
    }

    public boolean isSkipped() {
        return status == Status.SKIPPED;
    }

    public boolean isFailed() {
        return status == Status.FAILED;
    }

    public boolean isDegraded() {
        return status == Status.DEGRADED;
    }

    public boolean canContinue() {
        return status == Status.SUCCESS || status == Status.SKIPPED || status == Status.DEGRADED;
    }
}
