'use strict';

var LanguageExporter = require('../LanguageExporter.js');

/* ────────────────────────────────────────────────────────────────
   Rust Exporter — Bevy ECS Generation
   
   Exports visual scripts to Rust for Bevy game engine.
   Generates ECS components and systems following Bevy patterns.
──────────────────────────────────────────────────────────────── */
/* ── Rust Type Mapping ────────────────────────────────────────── */
const rustTypeMapping = {
    void: '()',
    bool: 'bool',
    int: 'i32',
    float: 'f32',
    string: 'String',
    vector2: 'Vec2',
    vector3: 'Vec3',
    color: 'Color',
    entity: 'Entity',
    array: 'Vec',
    dictionary: 'HashMap',
    any: 'Box<dyn Any>',
};
/* ── Rust Exporter ────────────────────────────────────────────── */
class RustExporter extends LanguageExporter.ImperativeLanguageExporter {
    constructor(config = {}) {
        super({
            targetEngine: 'bevy',
            indent: '    ',
            ...config,
        });
        this.languageName = 'rust';
        this.fileExtension = 'rs';
        this.typeMapping = rustTypeMapping;
        this.statementTerminator = ';';
        this.breakKeyword = 'break';
        this.continueKeyword = 'continue';
    }
    /* ── Main Generation ────────────────────────────────────────── */
    generateScript(script) {
        const builder = this.createBuilder();
        // File header
        if (script.headerComment) {
            builder.comment(script.headerComment);
        }
        builder.line('//! Generated by NiceToDev Visual Scripting');
        builder.line('//! Target: Bevy ECS');
        builder.emptyLine();
        // Allow common Rust lints
        builder.line('#![allow(dead_code)]');
        builder.line('#![allow(unused_variables)]');
        builder.emptyLine();
        // Standard imports
        builder.line('use bevy::prelude::*;');
        builder.line('use std::collections::HashMap;');
        builder.line('use std::any::Any;');
        builder.emptyLine();
        // Custom imports
        for (const imp of script.imports) {
            this.generateImport(imp, builder);
        }
        if (script.imports.length) {
            builder.emptyLine();
        }
        // Enums
        for (const en of script.enums || []) {
            this.generateEnum(en, builder);
            builder.emptyLine();
        }
        // Classes become Components/Resources in Bevy
        for (const cls of script.classes) {
            this.generateClass(cls, builder);
            builder.emptyLine();
        }
        // Top-level functions become systems
        for (const func of script.functions || []) {
            this.generateSystem(func, builder);
            builder.emptyLine();
        }
        // Plugin for Bevy
        if (script.classes.length > 0) {
            this.generatePlugin(script, builder);
        }
        return builder.toString();
    }
    generateImport(imp, builder) {
        var _a;
        if ((_a = imp.names) === null || _a === void 0 ? void 0 : _a.length) {
            builder.line(`use ${imp.module}::{${imp.names.join(', ')}};`);
        }
        else if (imp.alias) {
            builder.line(`use ${imp.module} as ${imp.alias};`);
        }
        else {
            builder.line(`use ${imp.module};`);
        }
    }
    generateEnum(en, builder) {
        builder.line('#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]');
        builder.line(`pub enum ${en.name} {`);
        builder.indent();
        for (const member of en.members) {
            if (member.value !== undefined) {
                builder.line(`${member.name} = ${member.value},`);
            }
            else {
                builder.line(`${member.name},`);
            }
        }
        builder.dedent();
        builder.line('}');
    }
    generateClass(cls, builder) {
        // Determine if this is a Component or Resource
        const isResource = cls.name.endsWith('Manager') || cls.name.endsWith('State');
        const derive = isResource ? '#[derive(Resource, Default)]' : '#[derive(Component, Default)]';
        // Doc comment
        if (cls.comment) {
            builder.docComment(cls.comment, 'csharp'); // Rust uses /// like C#
        }
        // Struct declaration
        builder.line(derive);
        builder.line(`pub struct ${cls.name} {`);
        builder.indent();
        // Fields
        for (const field of cls.fields) {
            this.generateField(field, builder);
        }
        builder.dedent();
        builder.line('}');
        builder.emptyLine();
        // Impl block for methods
        if (cls.methods.length > 0) {
            builder.line(`impl ${cls.name} {`);
            builder.indent();
            for (let i = 0; i < cls.methods.length; i++) {
                this.generateMethod(cls.methods[i], builder);
                if (i < cls.methods.length - 1) {
                    builder.emptyLine();
                }
            }
            builder.dedent();
            builder.line('}');
        }
    }
    generateField(field, builder) {
        if (field.comment) {
            builder.line(`/// ${field.comment}`);
        }
        const visibility = field.visibility === 'public' ? 'pub ' : '';
        const name = LanguageExporter.toSnakeCase(field.name);
        const typeName = field.fieldType ? this.mapType(field.fieldType) : 'Box<dyn Any>';
        builder.line(`${visibility}${name}: ${typeName},`);
    }
    generateMethod(method, builder) {
        var _a;
        // Doc comment
        if ((_a = method.attributes) === null || _a === void 0 ? void 0 : _a.includes('doc')) {
            builder.line(`/// Method: ${method.name}`);
        }
        const visibility = method.visibility === 'public' ? 'pub ' : '';
        const name = LanguageExporter.toSnakeCase(method.name);
        // Parameters with self
        const params = [];
        if (!method.isStatic) {
            params.push('&mut self');
        }
        params.push(...method.params.map((p) => this.formatParameter(p)));
        // Return type
        const returnType = method.returnType.type !== 'void' ? ` -> ${this.mapType(method.returnType)}` : '';
        builder.line(`${visibility}fn ${name}(${params.join(', ')})${returnType} {`);
        builder.indent();
        if (method.body.length === 0) {
            // Empty methods need a return value or unit
            if (method.returnType.type === 'void') {
                builder.line('// TODO: implement');
            }
            else {
                builder.line('todo!()');
            }
        }
        else {
            for (const stmt of method.body) {
                this.generateStatement(stmt, builder);
            }
        }
        builder.dedent();
        builder.line('}');
    }
    generateSystem(func, builder) {
        const name = LanguageExporter.toSnakeCase(func.name);
        builder.line(`/// Bevy system: ${func.name}`);
        builder.line(`pub fn ${name}_system(`);
        builder.indent();
        // System parameters (queries, resources, etc.)
        // Analyze function body to determine what we need
        builder.line('mut commands: Commands,');
        builder.line('time: Res<Time>,');
        // Add query parameters based on method parameters
        for (const param of func.params) {
            const paramType = this.mapType(param.paramType);
            builder.line(`${LanguageExporter.toSnakeCase(param.name)}: Query<&mut ${paramType}>,`);
        }
        builder.dedent();
        builder.line(') {');
        builder.indent();
        if (func.body.length === 0) {
            builder.line('// TODO: implement');
        }
        else {
            for (const stmt of func.body) {
                this.generateStatement(stmt, builder);
            }
        }
        builder.dedent();
        builder.line('}');
    }
    generatePlugin(script, builder) {
        const pluginName = `${LanguageExporter.toUpperCamelCase(script.name)}Plugin`;
        builder.line(`/// Plugin to register all components and systems`);
        builder.line(`pub struct ${pluginName};`);
        builder.emptyLine();
        builder.line(`impl Plugin for ${pluginName} {`);
        builder.indent();
        builder.line('fn build(&self, app: &mut App) {');
        builder.indent();
        // Register resources
        for (const cls of script.classes) {
            const isResource = cls.name.endsWith('Manager') || cls.name.endsWith('State');
            if (isResource) {
                builder.line(`app.init_resource::<${cls.name}>();`);
            }
        }
        // Register systems
        for (const func of script.functions || []) {
            const name = LanguageExporter.toSnakeCase(func.name);
            // Determine system set based on method name
            const isUpdate = func.name.toLowerCase().includes('update');
            const schedule = isUpdate ? 'Update' : 'Startup';
            builder.line(`app.add_systems(${schedule}, ${name}_system);`);
        }
        builder.dedent();
        builder.line('}');
        builder.dedent();
        builder.line('}');
    }
    formatParameter(param) {
        const name = LanguageExporter.toSnakeCase(param.name);
        const type = this.mapType(param.paramType);
        return `${name}: ${type}`;
    }
    /* ── Statement Generation ───────────────────────────────────── */
    generateVarDecl(decl, builder) {
        const mutKeyword = decl.isConst ? '' : 'mut ';
        const name = LanguageExporter.toSnakeCase(decl.name);
        const typeAnnotation = decl.varType && decl.varType.type !== 'any' ? `: ${this.mapType(decl.varType)}` : '';
        const init = decl.initializer ? ` = ${this.generateExpression(decl.initializer)}` : '';
        builder.line(`let ${mutKeyword}${name}${typeAnnotation}${init};`);
    }
    generateAssignment(assign, builder) {
        const target = this.generateExpression(assign.target);
        const value = this.generateExpression(assign.value);
        builder.line(`${target} ${assign.operator} ${value};`);
    }
    generateIf(stmt, builder) {
        var _a;
        const cond = this.generateExpression(stmt.condition);
        builder.line(`if ${cond} {`);
        builder.indent();
        for (const s of stmt.thenBranch) {
            this.generateStatement(s, builder);
        }
        builder.dedent();
        builder.line('}');
        for (const elseIf of stmt.elseIfs || []) {
            builder.line(`else if ${this.generateExpression(elseIf.condition)} {`);
            builder.indent();
            for (const s of elseIf.body) {
                this.generateStatement(s, builder);
            }
            builder.dedent();
            builder.line('}');
        }
        if ((_a = stmt.elseBranch) === null || _a === void 0 ? void 0 : _a.length) {
            builder.line('else {');
            builder.indent();
            for (const s of stmt.elseBranch) {
                this.generateStatement(s, builder);
            }
            builder.dedent();
            builder.line('}');
        }
    }
    generateWhile(stmt, builder) {
        const cond = this.generateExpression(stmt.condition);
        builder.line(`while ${cond} {`);
        builder.indent();
        for (const s of stmt.body) {
            this.generateStatement(s, builder);
        }
        builder.dedent();
        builder.line('}');
    }
    generateFor(stmt, builder) {
        // Convert to Rust loop pattern
        if (stmt.init) {
            this.generateStatement(stmt.init, builder);
        }
        builder.line('loop {');
        builder.indent();
        if (stmt.condition) {
            const cond = this.generateExpression(stmt.condition);
            builder.line(`if !(${cond}) { break; }`);
        }
        for (const s of stmt.body) {
            this.generateStatement(s, builder);
        }
        if (stmt.update) {
            builder.line(`${this.generateExpression(stmt.update)};`);
        }
        builder.dedent();
        builder.line('}');
    }
    generateForEach(stmt, builder) {
        const iterable = this.generateExpression(stmt.iterable);
        const variable = LanguageExporter.toSnakeCase(stmt.variable);
        builder.line(`for ${variable} in ${iterable}.iter() {`);
        builder.indent();
        for (const s of stmt.body) {
            this.generateStatement(s, builder);
        }
        builder.dedent();
        builder.line('}');
    }
    generateReturn(stmt, builder) {
        if (stmt.value) {
            builder.line(`return ${this.generateExpression(stmt.value)};`);
        }
        else {
            builder.line('return;');
        }
    }
    generateSwitch(stmt, builder) {
        var _a;
        const expr = this.generateExpression(stmt.expression);
        builder.line(`match ${expr} {`);
        builder.indent();
        for (const c of stmt.cases) {
            const caseVal = this.generateExpression(c.value);
            builder.line(`${caseVal} => {`);
            builder.indent();
            for (const s of c.body) {
                this.generateStatement(s, builder);
            }
            builder.dedent();
            builder.line('}');
        }
        if ((_a = stmt.defaultCase) === null || _a === void 0 ? void 0 : _a.length) {
            builder.line('_ => {');
            builder.indent();
            for (const s of stmt.defaultCase) {
                this.generateStatement(s, builder);
            }
            builder.dedent();
            builder.line('}');
        }
        else {
            builder.line('_ => {}');
        }
        builder.dedent();
        builder.line('}');
    }
    generateTry(stmt, builder) {
        var _a;
        // Rust doesn't have try/catch, use Result pattern
        this.addWarning('Rust uses Result<T, E> instead of try/catch');
        // Wrap in closure that returns Result
        builder.line('let result: Result<(), Box<dyn std::error::Error>> = (|| {');
        builder.indent();
        for (const s of stmt.tryBlock) {
            this.generateStatement(s, builder);
        }
        builder.line('Ok(())');
        builder.dedent();
        builder.line('})();');
        if ((_a = stmt.catchBlocks) === null || _a === void 0 ? void 0 : _a.length) {
            builder.line('if let Err(e) = result {');
            builder.indent();
            for (const s of stmt.catchBlocks[0].body) {
                this.generateStatement(s, builder);
            }
            builder.dedent();
            builder.line('}');
        }
    }
    /* ── Expression Generation ──────────────────────────────────── */
    generateLiteral(lit) {
        var _a;
        switch (lit.valueType) {
            case 'bool':
                return lit.value ? 'true' : 'false';
            case 'string':
                return `String::from("${LanguageExporter.escapeString(String(lit.value))}")`;
            case 'float':
                return `${lit.value}_f32`;
            case 'int':
                return `${lit.value}_i32`;
            case 'vector2': {
                const v = lit.value;
                return `Vec2::new(${v.x}_f32, ${v.y}_f32)`;
            }
            case 'vector3': {
                const v = lit.value;
                return `Vec3::new(${v.x}_f32, ${v.y}_f32, ${v.z}_f32)`;
            }
            case 'color': {
                const c = lit.value;
                return `Color::rgba(${c.r}_f32, ${c.g}_f32, ${c.b}_f32, ${(_a = c.a) !== null && _a !== void 0 ? _a : 1}_f32)`;
            }
            default:
                return lit.value === null ? 'None' : String(lit.value);
        }
    }
    generateBinaryOp(op) {
        const left = this.generateExpression(op.left);
        const right = this.generateExpression(op.right);
        return `(${left} ${op.operator} ${right})`;
    }
    generateUnaryOp(op) {
        const operand = this.generateExpression(op.operand);
        return op.prefix ? `${op.operator}${operand}` : `${operand}${op.operator}`;
    }
    generateCall(call) {
        var _a;
        const args = call.args.map((a) => this.generateExpression(a)).join(', ');
        const funcName = LanguageExporter.toSnakeCase(call.callee);
        const typeArgs = ((_a = call.typeArgs) === null || _a === void 0 ? void 0 : _a.length)
            ? `::<${call.typeArgs.map((t) => this.mapType(t)).join(', ')}>`
            : '';
        return `${funcName}${typeArgs}(${args})`;
    }
    generateMethodCall(call) {
        const obj = this.generateExpression(call.object);
        const args = call.args.map((a) => this.generateExpression(a)).join(', ');
        const methodName = LanguageExporter.toSnakeCase(call.method);
        return `${obj}.${methodName}(${args})`;
    }
    generatePropertyAccess(access) {
        const obj = this.generateExpression(access.object);
        return `${obj}.${LanguageExporter.toSnakeCase(access.property)}`;
    }
    generateIndexAccess(access) {
        const obj = this.generateExpression(access.object);
        const idx = this.generateExpression(access.index);
        return `${obj}[${idx}]`;
    }
    generateConditional(cond) {
        const condition = this.generateExpression(cond.condition);
        const ifTrue = this.generateExpression(cond.ifTrue);
        const ifFalse = this.generateExpression(cond.ifFalse);
        return `if ${condition} { ${ifTrue} } else { ${ifFalse} }`;
    }
    generateArrayLiteral(arr) {
        const elements = arr.elements.map((e) => this.generateExpression(e)).join(', ');
        return `vec![${elements}]`;
    }
    generateDictionaryLiteral(dict) {
        if (dict.entries.length === 0) {
            return 'HashMap::new()';
        }
        const entries = dict.entries
            .map((e) => `(${this.generateExpression(e.key)}, ${this.generateExpression(e.value)})`)
            .join(', ');
        return `HashMap::from([${entries}])`;
    }
    generateCast(cast) {
        const expr = this.generateExpression(cast.expression);
        const type = this.mapType(cast.targetType);
        return `${expr} as ${type}`;
    }
    generateLambda(lambda) {
        const params = lambda.params
            .map((p) => {
            const name = LanguageExporter.toSnakeCase(p.name);
            const type = this.mapType(p.paramType);
            return `${name}: ${type}`;
        })
            .join(', ');
        if (Array.isArray(lambda.body)) {
            // Multi-statement closure
            const bodyBuilder = this.createBuilder();
            for (const stmt of lambda.body) {
                this.generateStatement(stmt, bodyBuilder);
            }
            return `|${params}| { ${bodyBuilder.toString().trim()} }`;
        }
        else {
            const body = this.generateExpression(lambda.body);
            return `|${params}| ${body}`;
        }
    }
    generateNew(n) {
        const args = n.args.map((a) => this.generateExpression(a)).join(', ');
        // Rust uses Type::new() or Type { } for construction
        if (args) {
            return `${n.typeName}::new(${args})`;
        }
        return `${n.typeName}::default()`;
    }
    /* ── Rust-specific Helpers ──────────────────────────────────── */
    formatArrayType(elementType) {
        return `Vec<${elementType}>`;
    }
    formatDictType(keyType, valueType) {
        return `HashMap<${keyType}, ${valueType}>`;
    }
    formatNullableType(baseType) {
        return `Option<${baseType}>`;
    }
}

exports.RustExporter = RustExporter;
//# sourceMappingURL=RustExporter.js.map
