package p.studio.compiler.workspaces;

import lombok.extern.slf4j.Slf4j;
import p.studio.compiler.exceptions.BuildException;
import p.studio.compiler.messages.BuilderPipelineConfig;
import p.studio.compiler.models.BuilderPipelineContext;
import p.studio.compiler.workspaces.stages.*;
import p.studio.utilities.logs.LogAggregator;
import p.studio.utilities.structures.ReadOnlyCollection;

import java.util.List;

@Slf4j
public class BuilderPipelineService {
    public final static BuilderPipelineService INSTANCE;

    static {
        final var stages = List.<PipelineStage>of(
                new ResolveDepsPipelineStage(),
                new LoadSourcesPipelineStage(),
                new FrontendPhasePipelineStage(),
                new LowerToIRVMPipelineStage(),
                new OptimizeIRVMPipelineStage(),
                new EmitBytecodePipelineStage(),
                new LinkBytecodePipelineStage(),
                new VerifyBytecodePipelineStage(),
                new WriteBytecodeArtifactPipelineStage()
        );
        INSTANCE = new BuilderPipelineService(stages);
    }

    private final List<PipelineStage> stages;

    BuilderPipelineService(List<PipelineStage> stages) {
        this.stages = stages;
    }

    public void run(
            final BuilderPipelineConfig config,
            final LogAggregator logs) {
        final var ctx = BuilderPipelineContext.compilerContext(config);

        for (final var builderPipelineStage : stages) {
            final var issues = builderPipelineStage.run(ctx, logs);
            var error = false;
            if (ReadOnlyCollection.isNotEmpty(issues)) {
                for (final var issue : issues) {
                    if (issue.isError()) {
                        error = true;
                        logs.using(log).error(issue.getMessage(), issue.getException());
                        continue;
                    }
                    logs.using(log).warn(issue.getMessage());
                }
            }
            if (error) {
                throw new BuildException("issues found on pipeline stage: " + builderPipelineStage.getClass().getSimpleName());
            }
        }

        logs.using(log).info("builder pipeline completed successfully");
    }
}
