/**
 * .NET Semantic Registry — Loaded from tsbindgen `<Namespace>/bindings.json`
 *
 * This is a lightweight semantic index used by a few compiler passes
 * (e.g., override/shadow detection against CLR base classes).
 *
 * NOTE: tsbindgen no longer emits `.metadata.json`. All CLR semantics needed
 * by the compiler live in `bindings.json`.
 */
/**
 * Registry of all loaded .NET metadata
 * Maps fully-qualified type names to their metadata
 */
export class DotnetMetadataRegistry {
    constructor() {
        this.metadata = new Map();
    }
    buildModifiersKey(mods) {
        if (!mods || mods.length === 0)
            return "";
        return [...mods]
            .slice()
            .sort((a, b) => a.index - b.index)
            .map((m) => `${m.index}:${m.modifier}`)
            .join(",");
    }
    buildSignatureKey(parameterTypes, modifiersKey) {
        const typesKey = parameterTypes.join(",");
        const mods = modifiersKey ? `mods=${modifiersKey}` : "mods=";
        return `${typesKey}|${mods}`;
    }
    parseCanonicalParamTypes(canonicalSignature) {
        if (!canonicalSignature)
            return undefined;
        const match = canonicalSignature.match(/^\((.*)\):/);
        if (!match)
            return undefined;
        const paramsStr = match[1]?.trim() ?? "";
        if (paramsStr.length === 0)
            return [];
        // Split a comma-delimited type list, respecting nested bracket depth.
        // tsbindgen signatures use CLR-style nested generic brackets in some contexts.
        const result = [];
        let depth = 0;
        let current = "";
        for (const ch of paramsStr) {
            if (ch === "[") {
                depth++;
                current += ch;
            }
            else if (ch === "]") {
                depth--;
                current += ch;
            }
            else if (ch === "," && depth === 0) {
                result.push(current.trim());
                current = "";
            }
            else {
                current += ch;
            }
        }
        if (current.trim()) {
            result.push(current.trim());
        }
        return result;
    }
    /**
     * Load a tsbindgen bindings.json file and add its types to the registry.
     */
    loadBindingsFile(_filePath, content) {
        for (const type of content.types) {
            const kindMap = {
                Class: "class",
                Interface: "interface",
                Struct: "struct",
                Enum: "enum",
            };
            const kind = kindMap[type.kind ?? ""] ?? "class";
            const visibilityMap = {
                Public: "public",
                Protected: "protected",
                ProtectedInternal: "protected internal",
                Internal: "internal",
                Private: "private",
            };
            const properties = new Map();
            for (const prop of type.properties ?? []) {
                if (prop.isStatic)
                    continue;
                properties.set(prop.clrName, {
                    kind: "property",
                    virtual: prop.isVirtual === true || prop.isAbstract === true,
                    sealed: prop.isSealed === true,
                    abstract: prop.isAbstract === true,
                    visibility: visibilityMap[prop.visibility ?? ""] ?? undefined,
                });
            }
            const methods = new Map();
            for (const method of type.methods ?? []) {
                if (method.isStatic)
                    continue;
                const paramCount = method.parameterCount;
                if (typeof paramCount !== "number")
                    continue;
                const paramTypes = this.parseCanonicalParamTypes(method.canonicalSignature);
                if (!paramTypes)
                    continue;
                const modifiersKey = this.buildModifiersKey(method.parameterModifiers);
                const signatureKey = this.buildSignatureKey(paramTypes, modifiersKey);
                const byCount = methods.get(method.clrName) ??
                    new Map();
                const bySignature = byCount.get(paramCount) ?? new Map();
                const existing = bySignature.get(signatureKey);
                const next = existing
                    ? {
                        kind: "method",
                        virtual: existing.virtual === true ||
                            method.isVirtual === true ||
                            method.isAbstract === true,
                        sealed: existing.sealed === true || method.isSealed === true,
                        abstract: existing.abstract === true || method.isAbstract === true,
                        visibility: existing.visibility ??
                            visibilityMap[method.visibility ?? ""] ??
                            undefined,
                    }
                    : {
                        kind: "method",
                        virtual: method.isVirtual === true || method.isAbstract === true,
                        sealed: method.isSealed === true,
                        abstract: method.isAbstract === true,
                        visibility: visibilityMap[method.visibility ?? ""] ?? undefined,
                    };
                bySignature.set(signatureKey, next);
                byCount.set(paramCount, bySignature);
                methods.set(method.clrName, byCount);
            }
            this.metadata.set(type.clrName, {
                kind,
                baseType: type.baseType?.clrName,
                interfaces: type.interfaces?.map((i) => i.clrName) ?? [],
                methods,
                properties,
            });
        }
    }
    /**
     * Look up metadata for a .NET type by fully-qualified name
     */
    getTypeMetadata(qualifiedName) {
        return this.metadata.get(qualifiedName);
    }
    /**
     * Look up metadata for a specific CLR method overload by signature.
     *
     * Airplane-grade: requires a deterministic match by full parameter types + modifiers.
     */
    getMethodMetadata(qualifiedTypeName, methodName, parameterTypes, modifiersKey) {
        const signatureKey = this.buildSignatureKey(parameterTypes, modifiersKey);
        const visited = new Set();
        let current = qualifiedTypeName;
        while (current && !visited.has(current)) {
            visited.add(current);
            const typeMetadata = this.metadata.get(current);
            if (!typeMetadata)
                return undefined;
            const byCount = typeMetadata.methods.get(methodName);
            if (byCount) {
                const paramCount = parameterTypes.length;
                const bySignature = byCount.get(paramCount);
                if (bySignature) {
                    const found = bySignature.get(signatureKey);
                    if (found)
                        return found;
                }
            }
            current = typeMetadata.baseType;
        }
        return undefined;
    }
    getMethodOverloadCount(qualifiedTypeName, methodName, parameterCount) {
        const typeMetadata = this.metadata.get(qualifiedTypeName);
        if (!typeMetadata)
            return 0;
        const byCount = typeMetadata.methods.get(methodName);
        if (!byCount)
            return 0;
        const bySignature = byCount.get(parameterCount);
        return bySignature?.size ?? 0;
    }
    getPropertyMetadata(qualifiedTypeName, propertyName) {
        const visited = new Set();
        let current = qualifiedTypeName;
        while (current && !visited.has(current)) {
            visited.add(current);
            const typeMetadata = this.metadata.get(current);
            if (!typeMetadata)
                return undefined;
            const found = typeMetadata.properties.get(propertyName);
            if (found)
                return found;
            current = typeMetadata.baseType;
        }
        return undefined;
    }
    /**
     * Get all loaded type names
     */
    getAllTypeNames() {
        return Array.from(this.metadata.keys());
    }
    /**
     * Clear all loaded metadata
     */
    clear() {
        this.metadata.clear();
    }
}
/**
 * Build a method signature string for metadata lookup
 * Format: "MethodName(type1,type2,...)"
 * @param methodName The method name
 * @param parameterTypes Array of parameter type names (e.g., ["string", "number"])
 * @returns Signature string for metadata lookup
 */
export const buildMethodSignature = (methodName, parameterTypes) => {
    if (parameterTypes.length === 0) {
        return `${methodName}()`;
    }
    return `${methodName}(${parameterTypes.join(",")})`;
};
//# sourceMappingURL=dotnet-metadata.js.map