"use strict";
/**
 * Multi-language code generation from BB msgpack schema
 *
 * Architecture:
 *   Raw Schema → SchemaVisitor → CompiledSchema IR → Language Codegens → Files
 */
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = require("fs");
const path_1 = require("path");
const child_process_1 = require("child_process");
const util_1 = require("util");
const url_1 = require("url");
const msgpackr_1 = require("msgpackr");
const schema_visitor_js_1 = require("./schema_visitor.js");
const typescript_codegen_js_1 = require("./typescript_codegen.js");
const rust_codegen_js_1 = require("./rust_codegen.js");
const execAsync = (0, util_1.promisify)(child_process_1.exec);
const LANGUAGE_GENERATORS = [
    {
        name: 'TypeScript',
        enabled: true,
        generate: (compiled) => {
            const tsGen = new typescript_codegen_js_1.TypeScriptCodegen();
            return [
                { path: 'generated/api_types.ts', content: tsGen.generateTypes(compiled) },
                { path: 'generated/sync.ts', content: tsGen.generateSyncApi(compiled) },
                { path: 'generated/async.ts', content: tsGen.generateAsyncApi(compiled) },
            ];
        },
    },
    {
        name: 'Rust',
        enabled: true,
        generate: (compiled) => {
            const rustGen = new rust_codegen_js_1.RustCodegen();
            return [
                { path: '../../../rust/barretenberg-rs/src/generated_types.rs', content: rustGen.generateTypes(compiled) },
                { path: '../../../rust/barretenberg-rs/src/api.rs', content: rustGen.generateApi(compiled) },
            ];
        },
    },
];
// @ts-ignore
const __dirname = (0, path_1.dirname)((0, url_1.fileURLToPath)(""));
async function generate() {
    const bbBuildPath = process.env.BB_BINARY_PATH || (0, path_1.join)(__dirname, '../../../cpp/build/bin/bb');
    // Get schema from bb
    console.log('Fetching msgpack schema from bb...');
    const { stdout } = await execAsync(`${bbBuildPath} msgpack schema`);
    const schema = JSON.parse(stdout.trim());
    if (!schema.commands || !schema.responses) {
        throw new Error('Invalid schema: missing commands or responses');
    }
    // Compile schema once using visitor pattern
    console.log('Compiling schema...');
    const visitor = new schema_visitor_js_1.SchemaVisitor();
    const compiled = visitor.visit(schema.commands, schema.responses);
    console.log(`Found ${compiled.commands.length} commands, ${compiled.structs.size} structs\n`);
    // Ensure output directory exists
    const outputDir = (0, path_1.join)(__dirname, 'generated');
    (0, fs_1.mkdirSync)(outputDir, { recursive: true });
    // Generate all language bindings from compiled IR
    for (const generator of LANGUAGE_GENERATORS) {
        if (!generator.enabled) {
            console.log(`⊘ ${generator.name}: disabled`);
            continue;
        }
        const files = generator.generate(compiled);
        for (const file of files) {
            const outputPath = (0, path_1.join)(__dirname, file.path);
            (0, fs_1.mkdirSync)((0, path_1.dirname)(outputPath), { recursive: true });
            (0, fs_1.writeFileSync)(outputPath, file.content);
            console.log(`✓ ${generator.name}: ${outputPath}`);
        }
    }
    // Generate curve constants
    console.log('\nGenerating curve constants...');
    await generateCurveConstants(bbBuildPath, outputDir);
    console.log('\n✨ Generation complete! Clean, maintainable, multi-language architecture.');
}
async function generateCurveConstants(bbBuildPath, outputDir) {
    // Get curve constants from bb as msgpack binary
    const { stdout: constantsBuffer } = await execAsync(`${bbBuildPath} msgpack curve_constants`, {
        encoding: 'buffer',
        maxBuffer: 10 * 1024 * 1024, // 10MB buffer
    });
    // Decode msgpack
    const constants = (0, msgpackr_1.unpack)(constantsBuffer);
    // Helper to convert Uint8Array to hex string
    const toHex = (bytes) => '0x' + Buffer.from(bytes).toString('hex');
    // Helper to convert Uint8Array to bigint (big-endian)
    const toBigInt = (bytes) => {
        let result = 0n;
        for (const byte of bytes) {
            result = (result << 8n) | BigInt(byte);
        }
        return result;
    };
    // Helper to serialize point coordinate (handles both Uint8Array and array of Uint8Array for field2)
    const serializeCoordinate = (coord) => {
        if (Array.isArray(coord)) {
            // For field2 (like BN254 G2), we have array of two Uint8Arrays
            return `[${coord.map(c => `new Uint8Array([${Array.from(c).join(', ')}])`).join(', ')}]`;
        }
        else {
            // For regular fields, single Uint8Array
            return `new Uint8Array([${Array.from(coord).join(', ')}])`;
        }
    };
    // Generate TypeScript file
    const content = `/**
 * Curve constants generated from barretenberg native binary.
 * DO NOT EDIT - This file is auto-generated by generate.ts
 */

/**
 * BN254 curve constants
 */
export const BN254_FR_MODULUS = ${toBigInt(constants.bn254_fr_modulus)}n;
export const BN254_FQ_MODULUS = ${toBigInt(constants.bn254_fq_modulus)}n;

export const BN254_G1_GENERATOR = {
  x: ${serializeCoordinate(constants.bn254_g1_generator.x)},
  y: ${serializeCoordinate(constants.bn254_g1_generator.y)},
} as const;

export const BN254_G2_GENERATOR = {
  x: ${serializeCoordinate(constants.bn254_g2_generator.x)},
  y: ${serializeCoordinate(constants.bn254_g2_generator.y)},
} as const;

/**
 * Grumpkin curve constants
 */
export const GRUMPKIN_FR_MODULUS = ${toBigInt(constants.grumpkin_fr_modulus)}n;
export const GRUMPKIN_FQ_MODULUS = ${toBigInt(constants.grumpkin_fq_modulus)}n;

export const GRUMPKIN_G1_GENERATOR = {
  x: ${serializeCoordinate(constants.grumpkin_g1_generator.x)},
  y: ${serializeCoordinate(constants.grumpkin_g1_generator.y)},
} as const;

/**
 * Secp256k1 curve constants
 */
export const SECP256K1_FR_MODULUS = ${toBigInt(constants.secp256k1_fr_modulus)}n;
export const SECP256K1_FQ_MODULUS = ${toBigInt(constants.secp256k1_fq_modulus)}n;

export const SECP256K1_G1_GENERATOR = {
  x: ${serializeCoordinate(constants.secp256k1_g1_generator.x)},
  y: ${serializeCoordinate(constants.secp256k1_g1_generator.y)},
} as const;

/**
 * Secp256r1 curve constants
 */
export const SECP256R1_FR_MODULUS = ${toBigInt(constants.secp256r1_fr_modulus)}n;
export const SECP256R1_FQ_MODULUS = ${toBigInt(constants.secp256r1_fq_modulus)}n;

export const SECP256R1_G1_GENERATOR = {
  x: ${serializeCoordinate(constants.secp256r1_g1_generator.x)},
  y: ${serializeCoordinate(constants.secp256r1_g1_generator.y)},
} as const;
`;
    const outputPath = (0, path_1.join)(outputDir, 'curve_constants.ts');
    (0, fs_1.writeFileSync)(outputPath, content);
    console.log(`✓ Curve constants: ${outputPath}`);
}
// Run the generator
generate().catch(error => {
    console.error('Generation failed:', error);
    process.exit(1);
});
//# sourceMappingURL=data:application/json;base64, 