/**
 * Binding Registry - RegistryState type, signature parsing, alias resolution,
 * supertype/base-type helpers, and member overload resolution
 * (single owner + hierarchy walk).
 *
 * All functions in this module are pure (side-effect-free) and operate on an
 * explicit `RegistryState` parameter.
 *
 * Split from binding-registry-resolution.ts for file-size compliance (< 500 LOC).
 */
import { tsbindgenClrTypeNameToTsTypeName } from "../tsbindgen/names.js";
// ---------------------------------------------------------------------------
// Signature parsing
// ---------------------------------------------------------------------------
/**
 * Split a comma-delimited type list, respecting nested bracket depth.
 * tsbindgen signatures use CLR-style nested generic brackets in some contexts.
 */
export const splitSignatureTypeList = (str) => {
    const result = [];
    let depth = 0;
    let current = "";
    for (const char of str) {
        if (char === "[") {
            depth++;
            current += char;
        }
        else if (char === "]") {
            depth--;
            current += char;
        }
        else if (char === "," && depth === 0) {
            result.push(current.trim());
            current = "";
        }
        else {
            current += char;
        }
    }
    if (current.trim()) {
        result.push(current.trim());
    }
    return result;
};
// ---------------------------------------------------------------------------
// Simple binding helpers (used by resolution)
// ---------------------------------------------------------------------------
const getSimpleBindingMemberOwnerClrType = (descriptor) => descriptor.type;
// ---------------------------------------------------------------------------
// Alias resolution
// ---------------------------------------------------------------------------
export const resolveLookupAlias = (state, typeAlias) => state.typeLookupAliasMap.get(typeAlias) ?? typeAlias;
const resolveSimpleBindingMemberOwnerAlias = (state, typeAlias) => {
    const descriptor = state.simpleBindings.get(typeAlias);
    if (!descriptor)
        return undefined;
    const mapped = tsbindgenClrTypeNameToTsTypeName(getSimpleBindingMemberOwnerClrType(descriptor));
    if (!mapped || mapped === typeAlias)
        return undefined;
    return mapped;
};
// ---------------------------------------------------------------------------
// Supertype / base-type helpers
// ---------------------------------------------------------------------------
export const getDirectSupertypes = (state, typeAlias) => {
    const set = state.tsSupertypes.get(typeAlias);
    if (!set || set.size === 0)
        return [];
    return Array.from(set).sort((a, b) => a.localeCompare(b));
};
const getDirectBaseType = (state, typeAlias) => state.tsBaseTypes.get(typeAlias);
const getDirectInterfaceSupertypes = (state, typeAlias) => {
    const direct = getDirectSupertypes(state, typeAlias);
    const baseType = getDirectBaseType(state, typeAlias);
    return baseType
        ? direct.filter((candidate) => candidate !== baseType)
        : direct;
};
// ---------------------------------------------------------------------------
// Member lookup owner aliases
// ---------------------------------------------------------------------------
const getMemberLookupOwnerAliases = (state, typeAlias) => {
    const aliases = [];
    const seen = new Set();
    const push = (alias) => {
        if (!alias || seen.has(alias))
            return;
        seen.add(alias);
        aliases.push(alias);
    };
    push(typeAlias);
    if (typeAlias.endsWith("$protected")) {
        push(typeAlias.slice(0, -"$protected".length));
    }
    const mappedAlias = resolveSimpleBindingMemberOwnerAlias(state, typeAlias);
    push(mappedAlias);
    if (mappedAlias?.endsWith("$protected")) {
        push(mappedAlias.slice(0, -"$protected".length));
    }
    return aliases;
};
// ---------------------------------------------------------------------------
// Member overload resolution (single owner)
// ---------------------------------------------------------------------------
const resolveMemberOverloadsForOwner = (state, ownerAlias, memberAlias, preferredClrOwner) => {
    const resolved = state.memberOverloads.get(`${ownerAlias}.${memberAlias}`);
    if (!resolved || resolved.length === 0)
        return resolved;
    if (preferredClrOwner) {
        const preferredOwnerMatches = resolved.filter((binding) => binding.binding.type === preferredClrOwner);
        if (preferredOwnerMatches.length > 0) {
            return preferredOwnerMatches;
        }
        return undefined;
    }
    const ownerClrTypes = state.clrTypeNamesByAlias.get(ownerAlias);
    if (!ownerClrTypes || ownerClrTypes.size !== 1) {
        return resolved;
    }
    const [ownerClrType] = Array.from(ownerClrTypes);
    if (!ownerClrType)
        return resolved;
    const directOwnerMatches = resolved.filter((binding) => ownerClrTypes.has(binding.binding.type));
    return directOwnerMatches.length > 0 ? directOwnerMatches : resolved;
};
// ---------------------------------------------------------------------------
// Member overload resolution (hierarchy walk)
// ---------------------------------------------------------------------------
const resolveMemberOverloadsByHierarchy = (state, ownerAlias, memberAlias, preferredClrOwner) => {
    const direct = resolveMemberOverloadsForOwner(state, ownerAlias, memberAlias, preferredClrOwner);
    if (direct && direct.length > 0) {
        return direct;
    }
    const getTargetKey = (binding) => `${binding.binding.assembly}:${binding.binding.type}::${binding.binding.member}`;
    const getModifiersKey = (binding) => {
        const modifiers = binding.parameterModifiers ?? [];
        if (modifiers.length === 0)
            return "";
        return [...modifiers]
            .slice()
            .sort((a, b) => a.index - b.index)
            .map((mod) => `${mod.index}:${mod.modifier}`)
            .join(",");
    };
    const visited = new Set([ownerAlias]);
    let currentBase = getDirectBaseType(state, ownerAlias);
    while (currentBase) {
        if (visited.has(currentBase))
            break;
        visited.add(currentBase);
        const resolved = resolveMemberOverloadsForOwner(state, currentBase, memberAlias, preferredClrOwner);
        if (resolved && resolved.length > 0) {
            return resolved;
        }
        currentBase = getDirectBaseType(state, currentBase);
    }
    let frontier = [];
    const interfaceOwners = [ownerAlias];
    let baseForInterfaces = getDirectBaseType(state, ownerAlias);
    while (baseForInterfaces) {
        interfaceOwners.push(baseForInterfaces);
        baseForInterfaces = getDirectBaseType(state, baseForInterfaces);
    }
    for (const candidateOwner of interfaceOwners) {
        for (const iface of getDirectInterfaceSupertypes(state, candidateOwner)) {
            if (visited.has(iface))
                continue;
            visited.add(iface);
            frontier.push(iface);
        }
    }
    while (frontier.length > 0) {
        const nextFrontier = [];
        const resolvedAtDepth = [];
        for (const candidateAlias of frontier) {
            const resolved = resolveMemberOverloadsForOwner(state, candidateAlias, memberAlias, preferredClrOwner);
            if (resolved && resolved.length > 0) {
                resolvedAtDepth.push(resolved);
            }
            for (const superAlias of getDirectInterfaceSupertypes(state, candidateAlias)) {
                if (visited.has(superAlias))
                    continue;
                visited.add(superAlias);
                nextFrontier.push(superAlias);
            }
        }
        if (resolvedAtDepth.length > 0) {
            const first = resolvedAtDepth[0]?.[0];
            if (!first)
                return undefined;
            const targetKey = getTargetKey(first);
            const modifiersKey = getModifiersKey(first);
            for (const overloads of resolvedAtDepth) {
                const current = overloads[0];
                if (!current)
                    return undefined;
                if (getTargetKey(current) !== targetKey) {
                    return undefined;
                }
                if (getModifiersKey(current) !== modifiersKey) {
                    return undefined;
                }
                for (const overload of overloads) {
                    if (getTargetKey(overload) !== targetKey) {
                        return undefined;
                    }
                    if (getModifiersKey(overload) !== modifiersKey) {
                        return undefined;
                    }
                }
            }
            return resolvedAtDepth[0];
        }
        frontier = nextFrontier;
    }
    return undefined;
};
// ---------------------------------------------------------------------------
// Public member-overload resolution
// ---------------------------------------------------------------------------
/**
 * Look up all member bindings for a TS type alias + member alias.
 *
 * IMPORTANT: Methods can be overloaded, and overloads can differ in ref/out/in
 * modifiers (tsbindgen provides these via `parameterModifiers`). This accessor
 * preserves overload sets so the call converter can select the correct one.
 */
export const resolveMemberOverloads = (state, typeAlias, memberAlias, preferredClrOwner) => {
    const resolvedPreferredClrOwner = preferredClrOwner ??
        (state.clrTypeNames.has(typeAlias) ? typeAlias : undefined);
    const normalizedTypeAlias = resolveLookupAlias(state, typeAlias);
    const rootAliases = [];
    const seenRoots = new Set();
    const pushRootAlias = (alias) => {
        if (!alias || seenRoots.has(alias)) {
            return;
        }
        seenRoots.add(alias);
        rootAliases.push(alias);
    };
    pushRootAlias(typeAlias);
    pushRootAlias(normalizedTypeAlias);
    for (const rootAlias of rootAliases) {
        for (const ownerAlias of getMemberLookupOwnerAliases(state, rootAlias)) {
            const match = resolveMemberOverloadsByHierarchy(state, ownerAlias, memberAlias, resolvedPreferredClrOwner);
            if (match && match.length > 0)
                return match;
        }
    }
    return undefined;
};
//# sourceMappingURL=binding-registry-resolution-member.js.map