/**
 * Receiver substitution helpers.
 *
 * Contains computeReceiverSubstitution for receiver type parameter binding.
 *
 * DAG position: depends on type-system-state
 */
import { resolveTypeIdByName, normalizeToNominal, resolveSourceReferenceFQName, } from "./type-system-state.js";
const normalizeTsbindgenDeclaringTypeName = (name) => {
    if (name.endsWith("$instance")) {
        return name.slice(0, -"$instance".length);
    }
    if (name.startsWith("__") && name.endsWith("$views")) {
        return name.slice(2, -"$views".length);
    }
    return name;
};
const enumerateEquivalentDeclaringTypeNames = (name) => {
    const names = [];
    const push = (candidate) => {
        if (!candidate) {
            return;
        }
        if (!names.includes(candidate)) {
            names.push(candidate);
        }
    };
    const baseName = normalizeTsbindgenDeclaringTypeName(name);
    push(name);
    push(baseName);
    push(`${baseName}$instance`);
    push(`__${baseName}$views`);
    return names;
};
const resolveDeclaringTypeCandidates = (state, declaringTypeTsName, arityHint, declaringClrType) => {
    const candidates = [];
    const pushCandidate = (candidate) => {
        if (!candidate) {
            return;
        }
        if (candidates.some((existing) => existing.stableId === candidate.stableId)) {
            return;
        }
        candidates.push(candidate);
    };
    pushCandidate(declaringClrType
        ? resolveTypeIdByName(state, declaringClrType, arityHint)
        : undefined);
    pushCandidate(declaringClrType ? resolveTypeIdByName(state, declaringClrType) : undefined);
    for (const candidateName of enumerateEquivalentDeclaringTypeNames(declaringTypeTsName)) {
        const sourceFqName = resolveSourceReferenceFQName(state, {
            kind: "referenceType",
            name: candidateName,
        });
        if (sourceFqName) {
            pushCandidate(resolveTypeIdByName(state, sourceFqName, arityHint));
            pushCandidate(resolveTypeIdByName(state, sourceFqName));
        }
        pushCandidate(resolveTypeIdByName(state, candidateName, arityHint));
        pushCandidate(resolveTypeIdByName(state, candidateName));
    }
    return candidates;
};
// ─────────────────────────────────────────────────────────────────────────
// computeReceiverSubstitution — Receiver type → substitution map
// ─────────────────────────────────────────────────────────────────────────
const resolveDeclaringTypeParameterNames = (state, declaringTypeIds, explicitNames) => {
    if (explicitNames && explicitNames.length > 0) {
        return explicitNames;
    }
    for (const declaringTypeId of declaringTypeIds) {
        const typeParameters = state.unifiedCatalog
            .getTypeParameters(declaringTypeId)
            .map((parameter) => parameter.name);
        if (typeParameters.length > 0) {
            return typeParameters;
        }
    }
    return undefined;
};
/**
 * Compute receiver substitution for a method call.
 *
 * Given a receiver type (e.g., Array<string>) and a declaring type's TS name,
 * computes the substitution map for class type parameters.
 *
 * Phase 6: Uses TypeId-based NominalEnv.getInstantiation().
 */
export const computeReceiverSubstitution = (state, receiverType, declaringTypeTsName, _declaringMemberName, declaringTypeParameterNames, declaringClrType) => {
    const normalized = normalizeToNominal(state, receiverType);
    if (!normalized) {
        return undefined;
    }
    const arityHint = normalized.typeArgs.length > 0
        ? normalized.typeArgs.length
        : declaringTypeParameterNames?.length;
    const declaringTypeIds = resolveDeclaringTypeCandidates(state, declaringTypeTsName, arityHint, declaringClrType);
    const resolvedDeclaringTypeParameterNames = resolveDeclaringTypeParameterNames(state, declaringTypeIds, declaringTypeParameterNames);
    let emptyInstantiation;
    for (const declaringTypeId of declaringTypeIds) {
        const nominalInstantiation = state.nominalEnv.getInstantiation(normalized.typeId, normalized.typeArgs, declaringTypeId);
        if (nominalInstantiation && nominalInstantiation.size > 0) {
            return nominalInstantiation;
        }
        if (!emptyInstantiation && nominalInstantiation) {
            emptyInstantiation = nominalInstantiation;
        }
        if (resolvedDeclaringTypeParameterNames &&
            resolvedDeclaringTypeParameterNames.length > 0 &&
            normalized.typeId.stableId === declaringTypeId.stableId &&
            normalized.typeArgs.length === resolvedDeclaringTypeParameterNames.length) {
            const directSubstitutionEntries = resolvedDeclaringTypeParameterNames.flatMap((name, index) => {
                const typeArgument = normalized.typeArgs[index];
                return typeArgument ? [[name, typeArgument]] : [];
            });
            return new Map(directSubstitutionEntries);
        }
    }
    return emptyInstantiation ?? undefined;
};
//# sourceMappingURL=call-resolution-signatures-catalog.js.map