/**
 * Converts inference engine output to human-readable .specly format
 */
export class SpeclyConverter {
    /**
     * Convert a LogicalComponentSpec to .specly format string
     */
    static toSpecly(spec, componentName) {
        let output = '';
        // v3.1 format requires components container
        output += 'components:\n';
        // Component entry
        const compName = componentName || spec.name || 'GeneratedComponent';
        output += `  ${compName}:\n`;
        if (spec.version) {
            output += `    version: "${spec.version}"\n`;
        }
        if (spec.description) {
            output += `    description: "${spec.description}"\n`;
        }
        if (spec.tags && Array.isArray(spec.tags) && spec.tags.length > 0) {
            output += `    tags: [${spec.tags.map((t) => `"${t}"`).join(', ')}]\n`;
        }
        if (spec.export) {
            output += '    export:\n';
            const exportSection = spec.export;
            if (exportSection.models && Array.isArray(exportSection.models) && exportSection.models.length > 0) {
                output += `      models: [${exportSection.models.join(', ')}]\n`;
            }
            if (exportSection.controllers && Array.isArray(exportSection.controllers) && exportSection.controllers.length > 0) {
                output += `      controllers: [${exportSection.controllers.join(', ')}]\n`;
            }
        }
        // Add empty line after header
        output += '\n';
        // Models section
        const models = this.toNamedEntries(spec.models);
        if (models.length > 0) {
            output += '    models:\n';
            for (const [modelName, modelSpec] of models) {
                output += this.convertModel(modelName, modelSpec, 3);
            }
            output += '\n';
        }
        // Controllers section
        const controllers = this.toNamedEntries(spec.controllers);
        if (controllers.length > 0) {
            output += '    controllers:\n';
            for (const [controllerName, controllerSpec] of controllers) {
                output += this.convertController(controllerName, controllerSpec, 3);
            }
            output += '\n';
        }
        // Services section
        const services = this.toNamedEntries(spec.services);
        if (services.length > 0) {
            output += '    services:\n';
            for (const [serviceName, serviceSpec] of services) {
                output += this.convertService(serviceName, serviceSpec, 3);
            }
            output += '\n';
        }
        // Events section
        const events = this.toNamedEntries(spec.events);
        if (events.length > 0) {
            output += '    events:\n';
            for (const [eventName, eventSpec] of events) {
                output += this.convertEvent(eventName, eventSpec, 3);
            }
            output += '\n';
        }
        // Views section
        const views = this.toNamedEntries(spec.views);
        if (views.length > 0) {
            output += '    views:\n';
            for (const [viewName, viewSpec] of views) {
                output += this.convertView(viewName, viewSpec, 3);
            }
            output += '\n';
        }
        // Commands section (AST is array of CommandSpec with name property)
        if (spec.commands) {
            output += this.convertCommands(spec.commands, 2);
        }
        // Generic passthrough sections that inference doesn't generate
        const knownSections = new Set([
            'name', 'version', 'description', 'tags', 'export',
            'models', 'controllers', 'services', 'events', 'views', 'commands',
            // Internal inference engine properties — not part of specly format
            'commonDefinitions', 'namespace',
        ]);
        for (const [key, value] of Object.entries(spec)) {
            if (!knownSections.has(key) && value != null && typeof value !== 'function') {
                output += this.convertGenericSection(key, value, 2);
            }
        }
        return output.trim();
    }
    /**
     * Normalize entity data to [name, spec] entries.
     * Handles both object format { Name: spec } and array format [{ name: 'Name', ... }]
     */
    static toNamedEntries(data) {
        if (!data)
            return [];
        if (Array.isArray(data)) {
            return data
                .filter((item) => item && typeof item === 'object')
                .map((item) => {
                const { name, ...rest } = item;
                return [name || 'Unknown', rest];
            });
        }
        if (typeof data === 'object') {
            const entries = Object.entries(data);
            if (entries.length === 0)
                return [];
            return entries;
        }
        return [];
    }
    /**
     * Normalize attributes to [name, shorthandString] entries.
     * Handles object { name: "String required" } and array [{ name, type, required, ... }]
     */
    static toAttributeEntries(data) {
        if (!data)
            return [];
        if (Array.isArray(data)) {
            return data.map((attr) => {
                let shorthand = attr.type || 'String';
                if (attr.required)
                    shorthand += ' required';
                if (attr.unique)
                    shorthand += ' unique';
                if (attr.auto)
                    shorthand += ` auto=${attr.auto}`;
                if (attr.category)
                    shorthand += ` category=${attr.category}`;
                if (attr.default !== undefined)
                    shorthand += ` default=${attr.default}`;
                if (attr.values)
                    shorthand += ` values=[${attr.values.join(', ')}]`;
                return [attr.name || 'unknown', shorthand];
            });
        }
        // Object format — values are already shorthand strings
        return Object.entries(data).map(([name, spec]) => [name, String(spec)]);
    }
    /**
     * Normalize relationships to [name, shorthandString] entries.
     * Handles object { name: "belongsTo Target" } and array [{ name, type, target, ... }]
     */
    static toRelationshipEntries(data) {
        if (!data)
            return [];
        if (Array.isArray(data)) {
            return data.map((rel) => {
                let shorthand = rel.type || 'belongsTo';
                if (rel.target)
                    shorthand += ` ${rel.target}`;
                if (rel.cascade === true)
                    shorthand += ' cascade';
                if (rel.eager === true)
                    shorthand += ' eager';
                return [rel.name || 'unknown', shorthand];
            });
        }
        // Object format — could be shorthand strings or objects
        return Object.entries(data).map(([name, spec]) => {
            if (typeof spec === 'string')
                return [name, spec];
            const rel = spec;
            let shorthand = rel.type || 'belongsTo';
            if (rel.target)
                shorthand += ` ${rel.target}`;
            if (rel.cascade === true)
                shorthand += ' cascade';
            if (rel.eager === true)
                shorthand += ' eager';
            return [name, shorthand];
        });
    }
    static convertModel(name, model, indentLevel) {
        const indent = '  '.repeat(indentLevel);
        let output = `${indent}${name}:\n`;
        if (model.description) {
            output += `${indent}  description: "${model.description}"\n`;
        }
        // Attributes — handle both object { name: "String required" } and array [{ name, type, ... }]
        const attrs = this.toAttributeEntries(model.attributes);
        if (attrs.length > 0) {
            output += `${indent}  attributes:\n`;
            for (const [attrName, attrString] of attrs) {
                output += `${indent}    ${attrName}: ${attrString}\n`;
            }
        }
        // Relationships — handle both object and array formats
        const rels = this.toRelationshipEntries(model.relationships);
        if (rels.length > 0) {
            output += `${indent}  relationships:\n`;
            for (const [relName, relString] of rels) {
                output += `${indent}    ${relName}: ${relString}\n`;
            }
        }
        // Lifecycles — handle both object and array formats
        const lifecycles = this.toNamedEntries(model.lifecycles);
        if (lifecycles.length > 0) {
            output += `${indent}  lifecycles:\n`;
            for (const [lifecycleName, lifecycleSpec] of lifecycles) {
                output += `${indent}    ${lifecycleName}:\n`;
                const lifecycle = lifecycleSpec;
                // Convert to SpecLy flow format
                if (lifecycle.states && Array.isArray(lifecycle.states)) {
                    // Use flow format for simple state sequences
                    const flow = lifecycle.states.join(' -> ');
                    output += `${indent}      flow: ${flow}\n`;
                }
                // Handle ConventionProcessor shorthand format (type: 'shorthand')
                else if (lifecycle.type === 'shorthand' && lifecycle.states) {
                    // Convert back to human-readable flow syntax
                    const flow = lifecycle.states.join(' -> ');
                    output += `${indent}      flow: ${flow}\n`;
                }
                // Handle ConventionProcessor structured format (type: 'structured')
                else if (lifecycle.type === 'structured') {
                    if (lifecycle.states) {
                        const flow = lifecycle.states.join(' -> ');
                        output += `${indent}      flow: ${flow}\n`;
                    }
                    if (lifecycle.transitions) {
                        output += `${indent}      transitions:\n`;
                        for (const [actionName, transition] of Object.entries(lifecycle.transitions)) {
                            const trans = transition;
                            output += `${indent}        ${actionName}: ${trans.from} -> ${trans.to}\n`;
                        }
                    }
                }
                // Handle legacy transitions array format (backwards compatibility)
                else if (lifecycle.transitions && Array.isArray(lifecycle.transitions)) {
                    output += `${indent}      transitions:\n`;
                    lifecycle.transitions.forEach((transition) => {
                        output += `${indent}        ${transition.name}: ${transition.from} -> ${transition.to}\n`;
                    });
                }
                // Handle any other properties
                else {
                    for (const [key, value] of Object.entries(lifecycle)) {
                        if (key !== 'type' && key !== 'states' && key !== 'transitions') {
                            output += `${indent}      ${key}: ${value}\n`;
                        }
                    }
                }
            }
        }
        // Behaviors (Phase 4: Preserve model behaviors)
        if (model.behaviors && Object.keys(model.behaviors).length > 0) {
            output += `${indent}  behaviors:\n`;
            for (const [behaviorName, behaviorSpec] of Object.entries(model.behaviors)) {
                const behavior = behaviorSpec;
                output += `${indent}    ${behaviorName}:\n`;
                if (behavior.description) {
                    output += `${indent}      description: "${behavior.description}"\n`;
                }
                if (behavior.parameters && Object.keys(behavior.parameters).length > 0) {
                    output += `${indent}      parameters:\n`;
                    for (const [paramName, paramSpec] of Object.entries(behavior.parameters)) {
                        // Handle both string and object parameter formats
                        let paramString;
                        if (typeof paramSpec === 'string') {
                            paramString = paramSpec;
                        }
                        else if (typeof paramSpec === 'object' && paramSpec !== null) {
                            // Object format: { type: 'Integer', default: 1 } or { type: 'String', required: true }
                            const spec = paramSpec;
                            paramString = spec.type || 'String';
                            if (spec.required)
                                paramString += ' required';
                            else if (spec.optional)
                                paramString += ' optional';
                            if (spec.default !== undefined)
                                paramString += ` default=${spec.default}`;
                        }
                        else {
                            paramString = 'String required';
                        }
                        output += `${indent}        ${paramName}: ${paramString}\n`;
                    }
                }
                if (behavior.returns) {
                    output += `${indent}      returns: ${behavior.returns}\n`;
                }
                if (behavior.requires && Array.isArray(behavior.requires) && behavior.requires.length > 0) {
                    // Use inline format for short arrays (convention syntax)
                    if (behavior.requires.length <= 3) {
                        const items = behavior.requires.map((req) => `"${req}"`).join(', ');
                        output += `${indent}      requires: [${items}]\n`;
                    }
                    else {
                        output += `${indent}      requires:\n`;
                        behavior.requires.forEach((req) => {
                            output += `${indent}        - "${req}"\n`;
                        });
                    }
                }
                if (behavior.ensures && Array.isArray(behavior.ensures) && behavior.ensures.length > 0) {
                    // Use inline format for short arrays (convention syntax)
                    if (behavior.ensures.length <= 3) {
                        const items = behavior.ensures.map((ens) => `"${ens}"`).join(', ');
                        output += `${indent}      ensures: [${items}]\n`;
                    }
                    else {
                        output += `${indent}      ensures:\n`;
                        behavior.ensures.forEach((ens) => {
                            output += `${indent}        - "${ens}"\n`;
                        });
                    }
                }
                if (behavior.publishes && Array.isArray(behavior.publishes) && behavior.publishes.length > 0) {
                    // Use inline format for short arrays (convention syntax)
                    if (behavior.publishes.length <= 3) {
                        const items = behavior.publishes.map((event) => event).join(', ');
                        output += `${indent}      publishes: [${items}]\n`;
                    }
                    else {
                        output += `${indent}      publishes:\n`;
                        behavior.publishes.forEach((event) => {
                            output += `${indent}        - ${event}\n`;
                        });
                    }
                }
            }
        }
        output += '\n';
        return output;
    }
    static convertController(name, controller, indentLevel) {
        const indent = '  '.repeat(indentLevel);
        let output = `${indent}${name}:\n`;
        if (controller.description) {
            output += `${indent}  description: "${controller.description}"\n`;
        }
        if (controller.model) {
            output += `${indent}  model: ${controller.model}\n`;
        }
        // CURED operations
        if (controller.cured) {
            output += `${indent}  cured:\n`;
            for (const [actionName, actionSpec] of Object.entries(controller.cured)) {
                output += this.convertAction(actionName, actionSpec, indentLevel + 2);
            }
        }
        // Custom domain actions (separate from CURED)
        if (controller.customActions) {
            output += `${indent}  actions:\n`;
            for (const [actionName, actionSpec] of Object.entries(controller.customActions)) {
                output += this.convertAction(actionName, actionSpec, indentLevel + 2);
            }
        }
        output += '\n';
        return output;
    }
    static convertAction(name, action, indentLevel) {
        const indent = '  '.repeat(indentLevel);
        let output = `${indent}${name}:\n`;
        if (action.description) {
            output += `${indent}  description: "${action.description}"\n`;
        }
        // Parameters
        if (action.parameters) {
            output += `${indent}  parameters:\n`;
            for (const [paramName, paramSpec] of Object.entries(action.parameters)) {
                output += `${indent}    ${paramName}: ${paramSpec}\n`;
            }
        }
        // Returns
        if (action.returns) {
            output += `${indent}  returns: ${action.returns}\n`;
        }
        // Requires (use inline format for convention syntax)
        if (action.requires && Array.isArray(action.requires)) {
            if (action.requires.length <= 3) {
                const items = action.requires.map((req) => `"${req}"`).join(', ');
                output += `${indent}  requires: [${items}]\n`;
            }
            else {
                output += `${indent}  requires:\n`;
                action.requires.forEach((req) => {
                    output += `${indent}    - "${req}"\n`;
                });
            }
        }
        // Ensures (use inline format for convention syntax)
        if (action.ensures && Array.isArray(action.ensures)) {
            if (action.ensures.length <= 3) {
                const items = action.ensures.map((ens) => `"${ens}"`).join(', ');
                output += `${indent}  ensures: [${items}]\n`;
            }
            else {
                output += `${indent}  ensures:\n`;
                action.ensures.forEach((ens) => {
                    output += `${indent}    - "${ens}"\n`;
                });
            }
        }
        // Publishes (use inline format for convention syntax)
        if (action.publishes && Array.isArray(action.publishes)) {
            if (action.publishes.length <= 3) {
                const items = action.publishes.map((event) => event).join(', ');
                output += `${indent}  publishes: [${items}]\n`;
            }
            else {
                output += `${indent}  publishes:\n`;
                action.publishes.forEach((event) => {
                    output += `${indent}    - ${event}\n`;
                });
            }
        }
        return output;
    }
    static convertService(name, service, indentLevel) {
        const indent = '  '.repeat(indentLevel);
        let output = `${indent}${name}:\n`;
        if (service.description) {
            output += `${indent}  description: "${service.description}"\n`;
        }
        // Subscriptions
        if (service.subscribes_to) {
            output += `${indent}  subscribes_to:\n`;
            for (const [eventName, handlerName] of Object.entries(service.subscribes_to)) {
                output += `${indent}    ${eventName}: ${handlerName}\n`;
            }
        }
        // Operations
        if (service.operations) {
            output += `${indent}  operations:\n`;
            for (const [opName, opSpec] of Object.entries(service.operations)) {
                output += this.convertOperation(opName, opSpec, indentLevel + 2);
            }
        }
        output += '\n';
        return output;
    }
    static convertOperation(name, operation, indentLevel) {
        const indent = '  '.repeat(indentLevel);
        let output = `${indent}${name}:\n`;
        if (operation.description) {
            output += `${indent}  description: "${operation.description}"\n`;
        }
        // Parameters
        if (operation.parameters) {
            output += `${indent}  parameters:\n`;
            for (const [paramName, paramSpec] of Object.entries(operation.parameters)) {
                output += `${indent}    ${paramName}: ${paramSpec}\n`;
            }
        }
        // Returns
        if (operation.returns) {
            output += `${indent}  returns: ${operation.returns}\n`;
        }
        // Requires
        if (operation.requires && Array.isArray(operation.requires)) {
            output += `${indent}  requires:\n`;
            operation.requires.forEach((req) => {
                output += `${indent}    - "${req}"\n`;
            });
        }
        // Ensures
        if (operation.ensures && Array.isArray(operation.ensures)) {
            output += `${indent}  ensures:\n`;
            operation.ensures.forEach((ens) => {
                output += `${indent}    - "${ens}"\n`;
            });
        }
        return output;
    }
    static convertEvent(name, event, indentLevel) {
        const indent = '  '.repeat(indentLevel);
        let output = `${indent}${name}:\n`;
        if (event.description) {
            output += `${indent}  description: "${event.description}"\n`;
        }
        // Attributes
        if (event.attributes) {
            output += `${indent}  attributes:\n`;
            for (const [attrName, attrSpec] of Object.entries(event.attributes)) {
                output += `${indent}    ${attrName}: ${attrSpec}\n`;
            }
        }
        output += '\n';
        return output;
    }
    static convertView(name, view, indentLevel) {
        const indent = '  '.repeat(indentLevel);
        let output = `${indent}${name}:\n`;
        if (view.type) {
            output += `${indent}  type: ${view.type}\n`;
        }
        // Handle both 'model' (single or array) and 'models' (array)
        // Schema expects property name to be 'model' even for arrays
        if (view.model) {
            if (Array.isArray(view.model)) {
                // Use inline format for arrays (convention syntax)
                output += `${indent}  model: [${view.model.join(', ')}]\n`;
            }
            else {
                output += `${indent}  model: ${view.model}\n`;
            }
        }
        else if (view.models && Array.isArray(view.models)) {
            // Convert 'models' to 'model' for v3.3 schema compliance (inline format)
            output += `${indent}  model: [${view.models.join(', ')}]\n`;
        }
        if (view.description) {
            output += `${indent}  description: "${view.description}"\n`;
        }
        // Subscribes or subscribes_to (use inline format for convention syntax)
        if (view.subscribes_to && Array.isArray(view.subscribes_to)) {
            if (view.subscribes_to.length <= 5) {
                // Inline format for short arrays
                output += `${indent}  subscribes_to: [${view.subscribes_to.join(', ')}]\n`;
            }
            else {
                output += `${indent}  subscribes_to:\n`;
                view.subscribes_to.forEach((event) => {
                    output += `${indent}    - ${event}\n`;
                });
            }
        }
        else if (view.subscribes && Array.isArray(view.subscribes)) {
            if (view.subscribes.length <= 5) {
                // Inline format for short arrays
                output += `${indent}  subscribes: [${view.subscribes.join(', ')}]\n`;
            }
            else {
                output += `${indent}  subscribes:\n`;
                view.subscribes.forEach((event) => {
                    output += `${indent}    - ${event}\n`;
                });
            }
        }
        // UI Components (can be object or array)
        if (view.uiComponents) {
            output += `${indent}  uiComponents:\n`;
            if (Array.isArray(view.uiComponents)) {
                // Array format
                view.uiComponents.forEach((component) => {
                    output += `${indent}    - type: ${component.type}\n`;
                    if (component.properties) {
                        output += `${indent}      properties:\n`;
                        for (const [propName, propValue] of Object.entries(component.properties)) {
                            if (Array.isArray(propValue)) {
                                output += `${indent}        ${propName}:\n`;
                                propValue.forEach((item) => {
                                    if (typeof item === 'object' && item !== null) {
                                        // Handle object items in arrays
                                        if (item.name && item.label) {
                                            output += `${indent}          - name: ${item.name}\n`;
                                            output += `${indent}            label: ${this.formatValue(item.label)}\n`;
                                            if (item.icon)
                                                output += `${indent}            icon: ${item.icon}\n`;
                                            if (item.bulk !== undefined)
                                                output += `${indent}            bulk: ${item.bulk}\n`;
                                        }
                                        else {
                                            output += `${indent}          - ${this.formatComplexValue(item, indent + '            ')}\n`;
                                        }
                                    }
                                    else {
                                        output += `${indent}          - ${this.formatValue(item)}\n`;
                                    }
                                });
                            }
                            else if (typeof propValue === 'object' && propValue !== null) {
                                output += `${indent}        ${propName}:\n`;
                                for (const [subKey, subValue] of Object.entries(propValue)) {
                                    if (Array.isArray(subValue)) {
                                        output += `${indent}          ${subKey}:\n`;
                                        subValue.forEach((subItem) => {
                                            output += `${indent}            - ${this.formatValue(subItem)}\n`;
                                        });
                                    }
                                    else {
                                        output += `${indent}          ${subKey}: ${this.formatValue(subValue)}\n`;
                                    }
                                }
                            }
                            else {
                                output += `${indent}        ${propName}: ${this.formatValue(propValue)}\n`;
                            }
                        }
                    }
                });
            }
            else {
                // Object format (named components)
                for (const [compName, compSpec] of Object.entries(view.uiComponents)) {
                    const comp = compSpec;
                    output += `${indent}    ${compName}:\n`;
                    if (comp.type) {
                        output += `${indent}      type: ${comp.type}\n`;
                    }
                    if (comp.properties) {
                        output += `${indent}      properties:\n`;
                        for (const [propName, propValue] of Object.entries(comp.properties)) {
                            if (Array.isArray(propValue)) {
                                output += `${indent}        ${propName}:\n`;
                                propValue.forEach((item) => {
                                    if (typeof item === 'object' && item !== null) {
                                        // Special handling for form sections with fields
                                        if (propName === 'sections' && item.title && item.fields) {
                                            output += `${indent}          - title: ${this.formatValue(item.title)}\n`;
                                            output += `${indent}            fields:\n`;
                                            if (Array.isArray(item.fields)) {
                                                item.fields.forEach((field) => {
                                                    output += `${indent}              - name: ${field.name}\n`;
                                                    output += `${indent}                type: ${field.type}\n`;
                                                    if (field.label)
                                                        output += `${indent}                label: ${this.formatValue(field.label)}\n`;
                                                    if (field.required !== undefined)
                                                        output += `${indent}                required: ${field.required}\n`;
                                                    if (field.validation)
                                                        output += `${indent}                validation: ${this.formatValue(field.validation)}\n`;
                                                });
                                            }
                                        }
                                        else {
                                            // Format other object items properly
                                            const objEntries = Object.entries(item);
                                            if (objEntries.length === 1) {
                                                const [key, val] = objEntries[0];
                                                output += `${indent}          - ${key}: ${this.formatValue(val)}\n`;
                                            }
                                            else {
                                                output += `${indent}          -\n`;
                                                objEntries.forEach(([key, val]) => {
                                                    output += `${indent}            ${key}: ${this.formatValue(val)}\n`;
                                                });
                                            }
                                        }
                                    }
                                    else {
                                        output += `${indent}          - ${item}\n`;
                                    }
                                });
                            }
                            else if (typeof propValue === 'object' && propValue !== null) {
                                output += `${indent}        ${propName}:\n`;
                                for (const [subKey, subValue] of Object.entries(propValue)) {
                                    output += `${indent}          ${subKey}: ${this.formatValue(subValue)}\n`;
                                }
                            }
                            else {
                                output += `${indent}        ${propName}: ${this.formatValue(propValue)}\n`;
                            }
                        }
                    }
                }
            }
        }
        // Handle any other view properties
        // Note: 'models' is handled above and converted to 'model', so skip it here
        const handledProps = new Set(['type', 'model', 'models', 'description', 'subscribes_to', 'subscribes', 'uiComponents']);
        for (const [key, value] of Object.entries(view)) {
            if (!handledProps.has(key)) {
                if (Array.isArray(value)) {
                    output += `${indent}  ${key}:\n`;
                    value.forEach((item) => {
                        output += `${indent}    - ${this.formatValue(item)}\n`;
                    });
                }
                else if (typeof value === 'object' && value !== null) {
                    output += `${indent}  ${key}:\n`;
                    for (const [subKey, subValue] of Object.entries(value)) {
                        output += `${indent}    ${subKey}: ${this.formatValue(subValue)}\n`;
                    }
                }
                else {
                    output += `${indent}  ${key}: ${this.formatValue(value)}\n`;
                }
            }
        }
        output += '\n';
        return output;
    }
    static formatValue(value) {
        if (typeof value === 'string') {
            // Quote strings containing YAML-special chars or spaces
            if (/[ *&!|>{}\[\],%#@`'"?]/.test(value) || value === '' || value === 'true' || value === 'false' || value === 'null') {
                return `"${value.replace(/"/g, '\\"')}"`;
            }
            return value;
        }
        if (typeof value === 'boolean' || typeof value === 'number') {
            return String(value);
        }
        if (Array.isArray(value)) {
            return `[${value.map(v => this.formatValue(v)).join(', ')}]`;
        }
        if (typeof value === 'object' && value !== null) {
            // Handle simple objects by showing key-value pairs
            const entries = Object.entries(value);
            if (entries.length <= 3) {
                return `{ ${entries.map(([k, v]) => `${k}: ${this.formatValue(v)}`).join(', ')} }`;
            }
            return 'Object';
        }
        return String(value);
    }
    static formatComplexValue(value, indent) {
        if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
            let result = '';
            for (const [key, val] of Object.entries(value)) {
                if (Array.isArray(val)) {
                    result += `${key}:\n`;
                    val.forEach((item) => {
                        result += `${indent}  - ${this.formatValue(item)}\n`;
                    });
                }
                else {
                    result += `${key}: ${this.formatValue(val)}\n`;
                }
            }
            return result.trim();
        }
        return this.formatValue(value);
    }
    /**
     * Convert commands section (AST: array of CommandSpec or object keyed by name)
     */
    static convertCommands(commands, indentLevel) {
        const indent = '  '.repeat(indentLevel);
        let output = `${indent}commands:\n`;
        // Handle both array format (post-convention-processor) and object format (raw)
        const commandEntries = Array.isArray(commands)
            ? commands.map((cmd) => [cmd.name, cmd])
            : Object.entries(commands);
        for (const [cmdName, cmdSpec] of commandEntries) {
            output += this.convertCommand(cmdName, cmdSpec, indentLevel + 1);
        }
        return output;
    }
    static convertCommand(name, cmd, indentLevel) {
        const indent = '  '.repeat(indentLevel);
        let output = `${indent}${name}:\n`;
        if (cmd.description) {
            output += `${indent}  description: "${cmd.description}"\n`;
        }
        // Arguments
        if (cmd.arguments && Object.keys(cmd.arguments).length > 0) {
            output += `${indent}  arguments:\n`;
            for (const [argName, argDef] of Object.entries(cmd.arguments)) {
                output += this.convertCommandParam(argName, argDef, indentLevel + 2);
            }
        }
        // Flags
        if (cmd.flags && Object.keys(cmd.flags).length > 0) {
            output += `${indent}  flags:\n`;
            for (const [flagName, flagDef] of Object.entries(cmd.flags)) {
                output += this.convertCommandParam(flagName, flagDef, indentLevel + 2);
            }
        }
        // Returns
        if (cmd.returns) {
            output += `${indent}  returns: ${cmd.returns}\n`;
        }
        // Exit codes
        if (cmd.exitCodes && Object.keys(cmd.exitCodes).length > 0) {
            output += `${indent}  exitCodes:\n`;
            for (const [code, desc] of Object.entries(cmd.exitCodes)) {
                output += `${indent}    ${code}: "${desc}"\n`;
            }
        }
        // Subcommands (recursive)
        if (cmd.subcommands && Object.keys(cmd.subcommands).length > 0) {
            output += `${indent}  subcommands:\n`;
            for (const [subName, subDef] of Object.entries(cmd.subcommands)) {
                output += this.convertCommand(subName, subDef, indentLevel + 2);
            }
        }
        return output;
    }
    static convertCommandParam(name, param, indentLevel) {
        const indent = '  '.repeat(indentLevel);
        if (typeof param === 'string') {
            return `${indent}${name}: ${param}\n`;
        }
        let output = `${indent}${name}:\n`;
        if (param.type)
            output += `${indent}  type: ${param.type}\n`;
        if (param.required)
            output += `${indent}  required: true\n`;
        if (param.positional)
            output += `${indent}  positional: true\n`;
        if (param.default !== undefined)
            output += `${indent}  default: ${this.formatValue(param.default)}\n`;
        if (param.alias)
            output += `${indent}  alias: "${param.alias}"\n`;
        if (param.description)
            output += `${indent}  description: "${param.description}"\n`;
        return output;
    }
    /**
     * Generic section passthrough using yaml.dump-style recursive serialization
     * For sections like distributions, constraints, measures, promotions
     */
    static convertGenericSection(key, value, indentLevel) {
        const indent = '  '.repeat(indentLevel);
        // Array of objects with name property (convention-processed entities)
        if (Array.isArray(value)) {
            if (value.length === 0)
                return '';
            // Check if items have 'name' property — convert back to object format
            if (value[0] && typeof value[0] === 'object' && value[0].name) {
                let output = `${indent}${key}:\n`;
                for (const item of value) {
                    const { name, ...rest } = item;
                    output += `${indent}  ${name}:\n`;
                    output += this.serializeObject(rest, indentLevel + 2);
                }
                return output;
            }
            // Simple array
            let output = `${indent}${key}:\n`;
            for (const item of value) {
                if (typeof item === 'object' && item !== null) {
                    output += `${indent}  -\n`;
                    output += this.serializeObject(item, indentLevel + 2);
                }
                else {
                    output += `${indent}  - ${this.formatValue(item)}\n`;
                }
            }
            return output;
        }
        // Object
        if (typeof value === 'object' && value !== null) {
            if (Object.keys(value).length === 0)
                return '';
            let output = `${indent}${key}:\n`;
            output += this.serializeObject(value, indentLevel + 1);
            return output;
        }
        // Scalar
        return `${indent}${key}: ${this.formatValue(value)}\n`;
    }
    /**
     * Recursively serialize an object to YAML-like string
     */
    static serializeObject(obj, indentLevel) {
        const indent = '  '.repeat(indentLevel);
        let output = '';
        for (const [key, value] of Object.entries(obj)) {
            if (value == null || typeof value === 'function')
                continue;
            if (Array.isArray(value)) {
                if (value.length === 0)
                    continue;
                // Inline short arrays of scalars
                if (value.length <= 5 && value.every(v => typeof v !== 'object')) {
                    output += `${indent}${key}: [${value.map(v => this.formatValue(v)).join(', ')}]\n`;
                }
                else {
                    output += `${indent}${key}:\n`;
                    for (const item of value) {
                        if (typeof item === 'object' && item !== null) {
                            output += `${indent}  -\n`;
                            output += this.serializeObject(item, indentLevel + 2);
                        }
                        else {
                            output += `${indent}  - ${this.formatValue(item)}\n`;
                        }
                    }
                }
            }
            else if (typeof value === 'object') {
                output += `${indent}${key}:\n`;
                output += this.serializeObject(value, indentLevel + 1);
            }
            else {
                output += `${indent}${key}: ${this.formatValue(value)}\n`;
            }
        }
        return output;
    }
}
//# sourceMappingURL=specly-converter.js.map