package p.studio.compiler.pbs.lowering;

import p.studio.compiler.models.IRBackendExecutableFunction;
import p.studio.compiler.models.IRReservedMetadata;
import p.studio.compiler.messages.Addressable;
import p.studio.compiler.pbs.ast.PbsAst;
import p.studio.compiler.source.identifiers.CallableId;
import p.studio.compiler.source.identifiers.NameId;
import p.studio.compiler.source.tables.CallableSignatureRef;
import p.studio.compiler.source.tables.IntrinsicReference;
import p.studio.utilities.structures.ReadOnlyList;

import java.util.List;
import java.util.Map;

public class PbsExecutableLoweringModels {

    public record PbsExecutableLoweringResult(
            ReadOnlyList<IRBackendExecutableFunction> executableFunctions,
            ReadOnlyList<CallableSignatureRef> callableSignatures,
            ReadOnlyList<IntrinsicReference> intrinsicPool) {
    }

    record PbsLowerableCallable(
            String callableName,
            PbsAst.FunctionDecl functionDecl) {
    }

    record PbsCallableResolutionKey(
            NameId callableNameId,
            int arity) {
    }

    record PbsIntrinsicOwnerMethodKey(
            String ownerCanonicalName,
            String sourceMethodName) {
    }

    record PbsIntrinsicCanonicalKey(
            String canonicalName,
            long canonicalVersion) {
    }

    record PbsExecutableMetadataIndex(
            Map<NameId, List<IRReservedMetadata.HostMethodBinding>> hostByMethodName,
            Map<String, String> builtinCanonicalBySourceType,
            Map<NameId, String> builtinConstOwnerByNameId,
            Map<NameId, Integer> globalSlotByNameId,
            Map<NameId, PbsAst.ConstDecl> constDeclByNameId,
            Map<String, Addressable> addressableByAddress,
            Map<PbsIntrinsicOwnerMethodKey, List<IRReservedMetadata.IntrinsicSurface>> intrinsicByOwnerAndMethod,
            Map<PbsIntrinsicCanonicalKey, String> intrinsicReturnOwnerByCanonical) {
    }

    record PbsExecutableCallableRegistry(
            ReadOnlyList<PbsLowerableCallable> localCallables,
            Map<PbsLowerableCallable, CallableId> callableIdByDeclaration,
            Map<PbsCallableResolutionKey, List<CallableId>> callableIdsByNameAndArity,
            Map<CallableId, CallableSignatureRef> callableSignatureByCallableId,
            Map<CallableId, Integer> returnSlotsByCallableId,
            Map<CallableId, String> returnOwnerByCallableId,
            Map<CallableId, PbsTupleProjection> tupleProjectionByCallableId,
            ReadOnlyList<CallableSignatureRef> callableSignatures) {
    }

    record PbsTupleProjection(
            int slotCount,
            Map<String, PbsTupleFieldProjection> fieldsByLabel) {
    }

    record PbsTupleFieldProjection(
            String label,
            int slotOffset,
            int slotCount) {
    }

    record PbsLoweredExecutableBody(
            ReadOnlyList<IRBackendExecutableFunction.Instruction> instructions,
            int localSlots,
            int maxStackSlots) {
    }

    record PbsCalleeIdentity(
            NameId primaryCallableNameId,
            NameId secondaryCallableNameId,
            String memberSourceMethodName,
            NameId memberNameId) {
    }

    record PbsResolvedCallsiteCandidates(
            List<CallableId> callableCandidates,
            List<IRReservedMetadata.HostMethodBinding> hostCandidates,
            List<IRReservedMetadata.IntrinsicSurface> intrinsicCandidates) {
    }

    record PbsLoopTargets(
            String continueLabel,
            String breakLabel) {
    }

    enum PbsCallsiteCategory {
        CALLABLE,
        HOST,
        INTRINSIC
    }
}
