/**
 * IR Builder tests: Statement Conversion
 */
import { describe, it } from "mocha";
import { expect } from "chai";
import { buildIrModule } from "../builder.js";
import { runNumericProofPass } from "../validation/numeric-proof-pass.js";
import { runCallResolutionRefreshPass } from "../validation/call-resolution-refresh-pass.js";
import { validateIrSoundness } from "../validation/soundness-gate.js";
import { createProgramContext, createTestProgram } from "./_test-helpers.js";
describe("IR Builder", function () {
    this.timeout(90000);
    describe("Statement Conversion", () => {
        it("should convert function declarations", () => {
            const source = `
        export function add(a: number, b: number): number {
          return a + b;
        }
      `;
            const { testProgram, ctx, options } = createTestProgram(source);
            const sourceFile = testProgram.sourceFiles[0];
            if (!sourceFile)
                throw new Error("Failed to create source file");
            const result = buildIrModule(sourceFile, testProgram, options, ctx);
            expect(result.ok).to.equal(true);
            if (result.ok) {
                const body = result.value.body;
                expect(body).to.have.length(1);
                const firstItem = body[0];
                if (!firstItem)
                    throw new Error("Missing body item");
                expect(firstItem.kind).to.equal("functionDeclaration");
                const func = firstItem;
                expect(func.name).to.equal("add");
                expect(func.parameters).to.have.length(2);
                expect(func.isExported).to.equal(true);
            }
        });
        it("should convert variable declarations", () => {
            // Use explicit type annotation for object literal to avoid synthetic type generation
            const source = `
        interface Named { name: string }
        const x = 10;
        let y: string = "hello";
        export const z: Named = { name: "test" };
      `;
            const { testProgram, ctx, options } = createTestProgram(source);
            const sourceFile = testProgram.sourceFiles[0];
            if (!sourceFile)
                throw new Error("Failed to create source file");
            const result = buildIrModule(sourceFile, testProgram, options, ctx);
            expect(result.ok).to.equal(true);
            if (result.ok) {
                const body = result.value.body;
                // 4 statements: interface + 3 variable declarations
                expect(body).to.have.length(4);
                const firstDecl = body[0];
                expect(firstDecl.kind).to.equal("interfaceDeclaration");
                const firstVar = body[1];
                expect(firstVar.kind).to.equal("variableDeclaration");
                expect(firstVar.declarationKind).to.equal("const");
                const secondVar = body[2];
                expect(secondVar.declarationKind).to.equal("let");
                const thirdVar = body[3];
                expect(thirdVar.isExported).to.equal(true);
            }
        });
        it("reuses converted exported declarations for module exports", () => {
            const source = `
        export const config = {
          retries: 3,
          features: ["a", "b", "c"],
        };
      `;
            const { testProgram, ctx, options } = createTestProgram(source);
            const sourceFile = testProgram.sourceFiles[0];
            if (!sourceFile)
                throw new Error("Failed to create source file");
            const result = buildIrModule(sourceFile, testProgram, options, ctx);
            expect(result.ok).to.equal(true);
            if (!result.ok)
                return;
            const bodyDeclaration = result.value.body.find((statement) => statement.kind === "variableDeclaration");
            expect(bodyDeclaration).to.not.equal(undefined);
            if (!bodyDeclaration)
                return;
            const exportDeclaration = result.value.exports.find((entry) => entry.kind === "declaration" &&
                entry.declaration.kind === "variableDeclaration");
            expect(exportDeclaration).to.not.equal(undefined);
            if (!exportDeclaration)
                return;
            expect(exportDeclaration.declaration).to.equal(bodyDeclaration);
        });
        it("should convert class declarations", () => {
            const source = `
        export class User {
          private name: string;
          constructor(name: string) {
            this.name = name;
          }
          getName(): string {
            return this.name;
          }
        }
      `;
            const { testProgram, ctx, options } = createTestProgram(source);
            const sourceFile = testProgram.sourceFiles[0];
            if (!sourceFile)
                throw new Error("Failed to create source file");
            const result = buildIrModule(sourceFile, testProgram, options, ctx);
            expect(result.ok).to.equal(true);
            if (result.ok) {
                const body = result.value.body;
                expect(body).to.have.length(1);
                const cls = body[0];
                expect(cls.kind).to.equal("classDeclaration");
                expect(cls.name).to.equal("User");
                expect(cls.isExported).to.equal(true);
                expect(cls.members).to.have.length.greaterThan(0);
            }
        });
        it("preserves readonly-only constructor parameter properties as class members", () => {
            const source = `
        export class BoolValue {
          constructor(readonly value: boolean) {}
        }
      `;
            const { testProgram, ctx, options } = createTestProgram(source);
            const sourceFile = testProgram.sourceFiles[0];
            if (!sourceFile)
                throw new Error("Failed to create source file");
            const result = buildIrModule(sourceFile, testProgram, options, ctx);
            expect(result.ok).to.equal(true);
            if (!result.ok)
                return;
            const cls = result.value.body.find((stmt) => stmt.kind === "classDeclaration" && stmt.name === "BoolValue");
            expect(cls).to.not.equal(undefined);
            if (!cls)
                return;
            const valueProp = cls.members.find((member) => member.kind === "propertyDeclaration" && member.name === "value");
            expect(valueProp).to.not.equal(undefined);
            expect(valueProp?.kind).to.equal("propertyDeclaration");
            if (!valueProp || valueProp.kind !== "propertyDeclaration")
                return;
            expect(valueProp.isReadonly).to.equal(true);
            expect(valueProp.accessibility).to.equal("public");
            expect(valueProp.type).to.deep.equal({
                kind: "primitiveType",
                name: "boolean",
            });
        });
        it("places parameter-property assignments after a leading super call", () => {
            const source = `
        class Base {
          constructor(readonly tag: string) {}
        }

        export class Derived extends Base {
          constructor(readonly value: boolean) {
            super("ok");
          }
        }
      `;
            const { testProgram, ctx, options } = createTestProgram(source);
            const sourceFile = testProgram.sourceFiles[0];
            if (!sourceFile)
                throw new Error("Failed to create source file");
            const result = buildIrModule(sourceFile, testProgram, options, ctx);
            expect(result.ok).to.equal(true);
            if (!result.ok)
                return;
            const cls = result.value.body.find((stmt) => stmt.kind === "classDeclaration" && stmt.name === "Derived");
            expect(cls).to.not.equal(undefined);
            if (!cls)
                return;
            const ctor = cls.members.find((member) => member.kind === "constructorDeclaration");
            expect(ctor).to.not.equal(undefined);
            expect(ctor?.kind).to.equal("constructorDeclaration");
            if (!ctor || ctor.kind !== "constructorDeclaration" || !ctor.body)
                return;
            expect(ctor.body.statements[0]?.kind).to.equal("expressionStatement");
            expect(ctor.body.statements[1]?.kind).to.equal("expressionStatement");
            const firstExpr = ctor.body.statements[0];
            const secondExpr = ctor.body.statements[1];
            if (!firstExpr ||
                firstExpr.kind !== "expressionStatement" ||
                !secondExpr ||
                secondExpr.kind !== "expressionStatement") {
                return;
            }
            expect(firstExpr.expression.kind).to.equal("call");
            if (firstExpr.expression.kind === "call") {
                expect(firstExpr.expression.callee.kind).to.equal("identifier");
                if (firstExpr.expression.callee.kind === "identifier") {
                    expect(firstExpr.expression.callee.name).to.equal("super");
                }
                expect(firstExpr.expression.inferredType?.kind).to.equal("voidType");
            }
            expect(secondExpr.expression.kind).to.equal("assignment");
            if (secondExpr.expression.kind === "assignment") {
                expect(secondExpr.expression.left.kind).to.equal("memberAccess");
                if (secondExpr.expression.left.kind === "memberAccess") {
                    expect(secondExpr.expression.left.object.kind).to.equal("this");
                    expect(secondExpr.expression.left.property).to.equal("value");
                }
            }
            const soundness = validateIrSoundness([result.value]);
            expect(soundness.ok).to.equal(true);
            const numeric = runNumericProofPass([result.value]);
            expect(numeric.ok).to.equal(true);
            if (!numeric.ok)
                return;
            const refreshCtx = createProgramContext(testProgram, options);
            const refreshed = runCallResolutionRefreshPass(numeric.modules, refreshCtx);
            const refreshedClass = refreshed.modules[0]?.body.find((stmt) => stmt.kind === "classDeclaration" && stmt.name === "Derived");
            expect(refreshedClass).to.not.equal(undefined);
            if (!refreshedClass)
                return;
            const refreshedCtor = refreshedClass.members.find((member) => member.kind === "constructorDeclaration");
            expect(refreshedCtor).to.not.equal(undefined);
            expect(refreshedCtor?.kind).to.equal("constructorDeclaration");
            if (!refreshedCtor ||
                refreshedCtor.kind !== "constructorDeclaration" ||
                !refreshedCtor.body) {
                return;
            }
            const refreshedFirstStmt = refreshedCtor.body.statements[0];
            expect(refreshedFirstStmt?.kind).to.equal("expressionStatement");
            if (!refreshedFirstStmt ||
                refreshedFirstStmt.kind !== "expressionStatement" ||
                refreshedFirstStmt.expression.kind !== "call") {
                return;
            }
            expect(refreshedFirstStmt.expression.inferredType?.kind).to.equal("voidType");
            const refreshedSoundness = validateIrSoundness(refreshed.modules);
            expect(refreshedSoundness.ok).to.equal(true);
        });
    });
});
//# sourceMappingURL=statement-conversion.test.js.map