/**
 * Object/interface type conversion
 *
 * Phase 5 Step 4: Uses local parameter helper (no ProgramContext dependency).
 * Type conversion should NOT depend on statement conversion.
 */
import * as ts from "typescript";
import { convertBindingName } from "../../../syntax/binding-patterns.js";
import { tryResolveDeterministicPropertyName } from "../../../syntax/property-names.js";
/**
 * Convert TypeScript object literal type to IR type.
 *
 * Returns IrDictionaryType for pure index signature types like:
 * - `{ [k: string]: T }`
 * - `{ [k: number]: T }`
 *
 * Returns IrObjectType for regular object types with named members.
 */
export const convertObjectType = (node, binding, convertType) => {
    // Check for pure index signature type (no other members)
    const indexSignatures = node.members.filter(ts.isIndexSignatureDeclaration);
    const otherMembers = node.members.filter((m) => !ts.isIndexSignatureDeclaration(m));
    // If ONLY index signature(s) exist, convert to dictionary type
    const firstIndexSig = indexSignatures[0];
    if (firstIndexSig !== undefined && otherMembers.length === 0) {
        // Use the first index signature (TypeScript allows multiple, but we take first)
        const indexSig = firstIndexSig;
        const keyParam = indexSig.parameters[0];
        // Determine key type from parameter type
        const keyType = keyParam?.type
            ? convertKeyType(keyParam.type)
            : { kind: "primitiveType", name: "string" };
        // Determine value type - use anyType as marker if not specified
        // The IR soundness gate will catch this and emit TSN7414
        const valueType = indexSig.type
            ? convertType(indexSig.type, binding)
            : { kind: "anyType" };
        return {
            kind: "dictionaryType",
            keyType,
            valueType,
        };
    }
    // Regular object type with named members
    const members = [];
    node.members.forEach((member) => {
        if (ts.isPropertySignature(member) && member.type) {
            const memberName = tryResolveDeterministicPropertyName(member.name);
            if (!memberName) {
                return;
            }
            const propSig = {
                kind: "propertySignature",
                name: memberName,
                type: convertType(member.type, binding),
                isOptional: !!member.questionToken,
                isReadonly: !!member.modifiers?.some((m) => m.kind === ts.SyntaxKind.ReadonlyKeyword),
            };
            members.push(propSig);
        }
        else if (ts.isMethodSignature(member)) {
            const memberName = tryResolveDeterministicPropertyName(member.name);
            if (!memberName) {
                return;
            }
            const methSig = {
                kind: "methodSignature",
                name: memberName,
                parameters: convertTypeParameters(member.parameters, binding, convertType),
                returnType: member.type ? convertType(member.type, binding) : undefined,
            };
            members.push(methSig);
        }
    });
    return { kind: "objectType", members };
};
/**
 * Convert index signature key type to IR type.
 * Supported key domains are string, number, and symbol.
 */
const convertKeyType = (typeNode) => {
    if (typeNode.kind === ts.SyntaxKind.StringKeyword) {
        return { kind: "primitiveType", name: "string" };
    }
    if (typeNode.kind === ts.SyntaxKind.NumberKeyword) {
        return { kind: "primitiveType", name: "number" };
    }
    if (typeNode.kind === ts.SyntaxKind.SymbolKeyword ||
        (ts.isTypeReferenceNode(typeNode) &&
            ts.isIdentifier(typeNode.typeName) &&
            typeNode.typeName.text === "symbol")) {
        return { kind: "referenceType", name: "object" };
    }
    // Fallback to string for other cases
    return { kind: "primitiveType", name: "string" };
};
/**
 * Convert parameters for method signatures (no initializers, no ProgramContext).
 *
 * This is used for MethodSignature in type contexts.
 * Unlike statement-converter's convertParameters, this:
 * - Does NOT convert initializers (type signatures don't have them)
 * - Does NOT require ProgramContext
 * - Takes a convertType function for type node conversion
 */
const convertTypeParameters = (parameters, binding, convertType) => {
    return parameters.map((param) => {
        let passing = "value";
        let actualType = param.type;
        // Detect ref<T>, out<T>, in<T>, inref<T> wrapper types
        if (param.type &&
            ts.isTypeReferenceNode(param.type) &&
            ts.isIdentifier(param.type.typeName)) {
            const typeName = param.type.typeName.text;
            if ((typeName === "ref" ||
                typeName === "out" ||
                typeName === "in" ||
                typeName === "inref") &&
                param.type.typeArguments &&
                param.type.typeArguments.length > 0) {
                // Set passing mode (both "in" and "inref" map to C# "in")
                passing =
                    typeName === "in" || typeName === "inref"
                        ? "in"
                        : typeName;
                // Extract wrapped type
                actualType = param.type.typeArguments[0];
            }
        }
        // Convert type if present
        const paramType = actualType ? convertType(actualType, binding) : undefined;
        return {
            kind: "parameter",
            pattern: convertBindingName(param.name),
            type: paramType,
            // Type signatures don't have initializers
            initializer: undefined,
            isOptional: !!param.questionToken,
            isRest: !!param.dotDotDotToken,
            passing,
        };
    });
};
//# sourceMappingURL=objects.js.map