/**
 * Constructor conversion with parameter properties
 */
import * as ts from "typescript";
import { convertBlockStatement } from "../../control.js";
import { hasReadonlyModifier, getAccessibility, convertParameters, makeOptionalType, } from "../../helpers.js";
import { withParameterTypeEnv } from "../../../type-env.js";
const isParameterPropertyParameter = (param) => {
    const modifiers = ts.getModifiers(param);
    return (modifiers?.some((m) => m.kind === ts.SyntaxKind.PublicKeyword ||
        m.kind === ts.SyntaxKind.PrivateKeyword ||
        m.kind === ts.SyntaxKind.ProtectedKeyword ||
        m.kind === ts.SyntaxKind.ReadonlyKeyword) ?? false);
};
const isLeadingSuperCallStatement = (statement) => {
    if (statement.kind !== "expressionStatement") {
        return false;
    }
    const expression = statement.expression;
    return (expression.kind === "call" &&
        expression.callee.kind === "identifier" &&
        expression.callee.name === "super");
};
/**
 * Convert constructor declaration to IR
 */
export const convertConstructor = (node, ctx, constructorParams) => {
    const parameters = convertParameters(node.parameters, ctx);
    const bodyCtx = withParameterTypeEnv(ctx, node.parameters, parameters);
    const parameterPropertyAssignments = [];
    // Add assignments for parameter properties (parameters with explicit modifiers)
    if (constructorParams) {
        for (const param of constructorParams) {
            if (isParameterPropertyParameter(param) && ts.isIdentifier(param.name)) {
                // Create: this.name = name;
                parameterPropertyAssignments.push({
                    kind: "expressionStatement",
                    expression: {
                        kind: "assignment",
                        operator: "=",
                        left: {
                            kind: "memberAccess",
                            object: {
                                kind: "this",
                            },
                            property: param.name.text,
                            isComputed: false,
                            isOptional: false,
                        },
                        right: {
                            kind: "identifier",
                            name: param.name.text,
                        },
                    },
                });
            }
        }
    }
    // Add existing constructor body statements
    const statements = [];
    if (node.body) {
        const existingBody = convertBlockStatement(node.body, bodyCtx, undefined);
        const [first, ...rest] = existingBody.statements;
        if (first && isLeadingSuperCallStatement(first)) {
            statements.push(first, ...parameterPropertyAssignments, ...rest);
        }
        else {
            statements.push(...parameterPropertyAssignments, ...existingBody.statements);
        }
    }
    else {
        statements.push(...parameterPropertyAssignments);
    }
    return {
        kind: "constructorDeclaration",
        parameters,
        body: { kind: "blockStatement", statements },
        accessibility: getAccessibility(node),
    };
};
/**
 * Extract parameter properties from constructor
 */
export const extractParameterProperties = (constructor, ctx) => {
    if (!constructor) {
        return [];
    }
    const parameterProperties = [];
    for (const param of constructor.parameters) {
        if (!isParameterPropertyParameter(param)) {
            continue; // Not a parameter property
        }
        // Create a field declaration for this parameter property
        if (ts.isIdentifier(param.name)) {
            // PHASE 4 (Alice's spec): Use captureTypeSyntax + typeFromSyntax
            const accessibility = getAccessibility(param);
            const rawType = param.type
                ? ctx.typeSystem.typeFromSyntax(ctx.binding.captureTypeSyntax(param.type))
                : undefined;
            const type = rawType && param.questionToken ? makeOptionalType(rawType) : rawType;
            parameterProperties.push({
                kind: "propertyDeclaration",
                name: param.name.text,
                type,
                initializer: undefined, // Will be assigned in constructor
                isStatic: false,
                isReadonly: hasReadonlyModifier(param),
                accessibility,
            });
        }
    }
    return parameterProperties;
};
//# sourceMappingURL=constructors.js.map