package p.studio.compiler.services;

import p.studio.compiler.models.SourceKind;
import p.studio.compiler.pbs.ast.PbsAst;
import p.studio.compiler.pbs.semantics.PbsSemanticsErrors;
import p.studio.compiler.source.diagnostics.DiagnosticSink;

import java.util.ArrayList;

final class PbsProjectLifecycleSemanticsValidator {

    void validate(
            final java.util.List<PbsParsedSourceFile> parsedSourceFiles,
            final DiagnosticSink diagnostics) {
        final var frames = new ArrayList<PbsAst.FunctionDecl>();
        var sawExecutableSource = false;

        for (final var parsedSource : parsedSourceFiles) {
            if (parsedSource.sourceKind() == SourceKind.SDK_INTERFACE) {
                continue;
            }
            sawExecutableSource = true;
            for (final var topDecl : parsedSource.ast().topDecls()) {
                if (!(topDecl instanceof PbsAst.FunctionDecl functionDecl)) {
                    continue;
                }
                if (functionDecl.lifecycleMarker() == PbsAst.LifecycleMarker.FRAME) {
                    frames.add(functionDecl);
                }
            }
        }

        if (!sawExecutableSource) {
            return;
        }
        if (frames.isEmpty()) {
            p.studio.compiler.source.diagnostics.Diagnostics.error(
                    diagnostics,
                    PbsSemanticsErrors.E_SEM_MISSING_PROJECT_FRAME.name(),
                    "Executable projects must declare exactly one [Frame] function",
                    parsedSourceFiles.getFirst().ast().span());
            return;
        }
        if (frames.size() <= 1) {
            return;
        }
        for (int i = 1; i < frames.size(); i++) {
            p.studio.compiler.source.diagnostics.Diagnostics.error(
                    diagnostics,
                    PbsSemanticsErrors.E_SEM_DUPLICATE_PROJECT_FRAME.name(),
                    "Executable projects may declare only one [Frame] function",
                    frames.get(i).span());
        }
    }
}
