package p.studio.compiler.backend.irvm;

import java.util.Map;
import java.util.Set;

public final class IRVMProfileFeatureGate {
    private final Map<String, Set<IRVMOp>> allowedByProfile;

    public IRVMProfileFeatureGate() {
        this(Map.of(
                "core-v1", Set.of(
                        IRVMOp.HALT,
                        IRVMOp.RET,
                        IRVMOp.PUSH_CONST,
                        IRVMOp.POP,
                        IRVMOp.GET_GLOBAL,
                        IRVMOp.GET_LOCAL,
                        IRVMOp.SET_GLOBAL,
                        IRVMOp.SET_LOCAL,
                        IRVMOp.CALL,
                        IRVMOp.JMP,
                        IRVMOp.JMP_IF_TRUE,
                        IRVMOp.JMP_IF_FALSE,
                        IRVMOp.HOSTCALL,
                        IRVMOp.INTRINSIC,
                        IRVMOp.PUSH_BOOL,
                        IRVMOp.ADD,
                        IRVMOp.SUB,
                        IRVMOp.MUL,
                        IRVMOp.DIV,
                        IRVMOp.MOD,
                        IRVMOp.EQ,
                        IRVMOp.NEQ,
                        IRVMOp.LT,
                        IRVMOp.LTE,
                        IRVMOp.GT,
                        IRVMOp.GTE,
                        IRVMOp.AND,
                        IRVMOp.OR,
                        IRVMOp.NOT,
                        IRVMOp.NEG,
                        IRVMOp.PUSH_I32),
                "experimental-v1", Set.of(
                        IRVMOp.HALT,
                        IRVMOp.RET,
                        IRVMOp.PUSH_CONST,
                        IRVMOp.POP,
                        IRVMOp.GET_GLOBAL,
                        IRVMOp.GET_LOCAL,
                        IRVMOp.SET_GLOBAL,
                        IRVMOp.SET_LOCAL,
                        IRVMOp.CALL,
                        IRVMOp.JMP,
                        IRVMOp.JMP_IF_TRUE,
                        IRVMOp.JMP_IF_FALSE,
                        IRVMOp.HOSTCALL,
                        IRVMOp.INTRINSIC,
                        IRVMOp.PUSH_BOOL,
                        IRVMOp.ADD,
                        IRVMOp.SUB,
                        IRVMOp.MUL,
                        IRVMOp.DIV,
                        IRVMOp.MOD,
                        IRVMOp.EQ,
                        IRVMOp.NEQ,
                        IRVMOp.LT,
                        IRVMOp.LTE,
                        IRVMOp.GT,
                        IRVMOp.GTE,
                        IRVMOp.AND,
                        IRVMOp.OR,
                        IRVMOp.NOT,
                        IRVMOp.NEG,
                        IRVMOp.PUSH_I32,
                        IRVMOp.INTERNAL_EXT)));
    }

    IRVMProfileFeatureGate(final Map<String, Set<IRVMOp>> allowedByProfile) {
        this.allowedByProfile = allowedByProfile == null ? Map.of() : Map.copyOf(allowedByProfile);
    }

    public String normalizeProfile(final String profile) {
        return profile == null || profile.isBlank() ? "core-v1" : profile;
    }

    public boolean isSupportedProfile(final String profile) {
        return allowedByProfile.containsKey(normalizeProfile(profile));
    }

    public boolean isAllowed(
            final String profile,
            final IRVMOp op) {
        final var allowed = allowedByProfile.get(normalizeProfile(profile));
        return allowed != null && allowed.contains(op);
    }
}
