package p.studio.compiler.pbs.semantics;

import p.studio.compiler.pbs.ast.PbsAst;
import p.studio.compiler.pbs.semantics.PbsFlowSemanticSupport.TypeView;
import p.studio.utilities.structures.ReadOnlyList;

final class PbsFlowCallableBodyAnalyzer {
    @FunctionalInterface
    interface BlockAnalysisDelegate {
        TypeView analyze(PbsAst.Block block, PbsFlowBodyContext context, boolean valueContext);
    }

    private final PbsFlowTypeOps typeOps;
    private final PbsFlowCompletionAnalyzer completionAnalyzer;
    private final BlockAnalysisDelegate blockAnalysisDelegate;

    PbsFlowCallableBodyAnalyzer(
            final PbsFlowTypeOps typeOps,
            final PbsFlowCompletionAnalyzer completionAnalyzer,
            final BlockAnalysisDelegate blockAnalysisDelegate) {
        this.typeOps = typeOps;
        this.completionAnalyzer = completionAnalyzer;
        this.blockAnalysisDelegate = blockAnalysisDelegate;
    }

    void validateCallableBody(
            final ReadOnlyList<PbsAst.Parameter> parameters,
            final PbsAst.Block body,
            final PbsFlowBodyContext context) {
        final var scope = context.scope();
        for (final var parameter : parameters) {
            scope.bind(
                    parameter.name(),
                    typeOps.typeFromTypeRef(parameter.typeRef(), context.model(), context.receiverType()));
        }
        final var callableContext = context.withScope(scope);
        blockAnalysisDelegate.analyze(body, callableContext, true);
        completionAnalyzer.validateCallableCompletion(body, callableContext);
    }
}
