import { ZSH_DYNAMIC_HELPERS } from '../templates/zsh-templates.js';
/**
 * Generates Zsh completion scripts for the OpenSpec CLI.
 * Follows Zsh completion system conventions using the _openspec function.
 */
export class ZshGenerator {
    shell = 'zsh';
    /**
     * Generate a Zsh completion script
     *
     * @param commands - Command definitions to generate completions for
     * @returns Zsh completion script as a string
     */
    generate(commands) {
        // Build command list using push() for loop clarity
        const commandLines = [];
        for (const cmd of commands) {
            const escapedDesc = this.escapeDescription(cmd.description);
            commandLines.push(`    '${cmd.name}:${escapedDesc}'`);
        }
        const commandList = commandLines.join('\n');
        // Build command cases using push() for loop clarity
        const commandCaseLines = [];
        for (const cmd of commands) {
            commandCaseLines.push(`        ${cmd.name})`);
            commandCaseLines.push(`          _openspec_${this.sanitizeFunctionName(cmd.name)}`);
            commandCaseLines.push('          ;;');
        }
        const commandCases = commandCaseLines.join('\n');
        // Build command functions using push() for loop clarity
        const commandFunctionLines = [];
        for (const cmd of commands) {
            commandFunctionLines.push(...this.generateCommandFunction(cmd));
            commandFunctionLines.push('');
        }
        const commandFunctions = commandFunctionLines.join('\n');
        // Dynamic completion helpers from template
        const helpers = ZSH_DYNAMIC_HELPERS;
        // Assemble final script with template literal
        return `#compdef openspec

# Zsh completion script for OpenSpec CLI
# Auto-generated - do not edit manually

_openspec() {
  local context state line
  typeset -A opt_args

  local -a commands
  commands=(
${commandList}
  )

  _arguments -C \\
    "1: :->command" \\
    "*::arg:->args"

  case $state in
    command)
      _describe "openspec command" commands
      ;;
    args)
      case $words[1] in
${commandCases}
      esac
      ;;
  esac
}

${commandFunctions}
${helpers}
compdef _openspec openspec
`;
    }
    /**
     * Generate completion function for a specific command
     */
    generateCommandFunction(cmd) {
        const funcName = `_openspec_${this.sanitizeFunctionName(cmd.name)}`;
        const lines = [];
        lines.push(`${funcName}() {`);
        // If command has subcommands, handle them
        if (cmd.subcommands && cmd.subcommands.length > 0) {
            lines.push('  local context state line');
            lines.push('  typeset -A opt_args');
            lines.push('');
            lines.push('  local -a subcommands');
            lines.push('  subcommands=(');
            for (const subcmd of cmd.subcommands) {
                const escapedDesc = this.escapeDescription(subcmd.description);
                lines.push(`    '${subcmd.name}:${escapedDesc}'`);
            }
            lines.push('  )');
            lines.push('');
            lines.push('  _arguments -C \\');
            // Add command flags
            for (const flag of cmd.flags) {
                lines.push('    ' + this.generateFlagSpec(flag) + ' \\');
            }
            lines.push('    "1: :->subcommand" \\');
            lines.push('    "*::arg:->args"');
            lines.push('');
            lines.push('  case $state in');
            lines.push('    subcommand)');
            lines.push('      _describe "subcommand" subcommands');
            lines.push('      ;;');
            lines.push('    args)');
            lines.push('      case $words[1] in');
            for (const subcmd of cmd.subcommands) {
                lines.push(`        ${subcmd.name})`);
                lines.push(`          _openspec_${this.sanitizeFunctionName(cmd.name)}_${this.sanitizeFunctionName(subcmd.name)}`);
                lines.push('          ;;');
            }
            lines.push('      esac');
            lines.push('      ;;');
            lines.push('  esac');
        }
        else {
            // Command without subcommands
            lines.push('  _arguments \\');
            // Add flags
            for (const flag of cmd.flags) {
                lines.push('    ' + this.generateFlagSpec(flag) + ' \\');
            }
            this.appendPositionalSpecs(lines, cmd);
        }
        lines.push('}');
        // Generate subcommand functions if they exist
        if (cmd.subcommands) {
            for (const subcmd of cmd.subcommands) {
                lines.push('');
                lines.push(...this.generateSubcommandFunction(cmd.name, subcmd));
            }
        }
        return lines;
    }
    /**
     * Generate completion function for a subcommand
     */
    generateSubcommandFunction(parentName, subcmd) {
        const funcName = `_openspec_${this.sanitizeFunctionName(parentName)}_${this.sanitizeFunctionName(subcmd.name)}`;
        const lines = [];
        lines.push(`${funcName}() {`);
        lines.push('  _arguments \\');
        // Add flags
        for (const flag of subcmd.flags) {
            lines.push('    ' + this.generateFlagSpec(flag) + ' \\');
        }
        this.appendPositionalSpecs(lines, subcmd);
        lines.push('}');
        return lines;
    }
    /**
     * Generate flag specification for _arguments
     */
    generateFlagSpec(flag) {
        const parts = [];
        // Handle mutually exclusive short and long forms
        if (flag.short) {
            parts.push(`'(-${flag.short} --${flag.name})'{-${flag.short},--${flag.name}}'`);
        }
        else {
            parts.push(`'--${flag.name}`);
        }
        // Add description
        const escapedDesc = this.escapeDescription(flag.description);
        parts.push(`[${escapedDesc}]`);
        // Add value completion if flag takes a value
        if (flag.takesValue) {
            if (flag.values && flag.values.length > 0) {
                // Provide specific value completions
                const valueList = flag.values.map(v => this.escapeValue(v)).join(' ');
                parts.push(`:value:(${valueList})`);
            }
            else {
                // Generic value placeholder
                parts.push(':value:');
            }
        }
        // Close the quote (needed for both short and long forms)
        parts.push("'");
        return parts.join('');
    }
    /**
     * Generate positional argument specification
     */
    generatePositionalSpec(positionalType) {
        switch (positionalType) {
            case 'change-id':
                return "'*: :_openspec_complete_changes'";
            case 'spec-id':
                return "'*: :_openspec_complete_specs'";
            case 'change-or-spec-id':
                return "'*: :_openspec_complete_items'";
            case 'schema-name':
                return "'*: :_openspec_complete_schemas'";
            case 'path':
                return "'*:path:_files'";
            case 'shell':
                return "'*:shell:(zsh bash fish powershell)'";
            default:
                return "'*: :_default'";
        }
    }
    appendPositionalSpecs(lines, cmd) {
        const positionalSpecs = this.generatePositionalSpecs(cmd);
        if (positionalSpecs.length === 0) {
            if (lines[lines.length - 1].endsWith(' \\')) {
                lines[lines.length - 1] = lines[lines.length - 1].slice(0, -2);
            }
            return;
        }
        for (const [index, spec] of positionalSpecs.entries()) {
            const suffix = index === positionalSpecs.length - 1 ? '' : ' \\';
            lines.push('    ' + spec + suffix);
        }
    }
    generatePositionalSpecs(cmd) {
        if (cmd.positionals && cmd.positionals.length > 0) {
            return cmd.positionals.map((positional, index) => this.generateIndexedPositionalSpec(positional, index + 1));
        }
        if (cmd.acceptsPositional) {
            return [this.generatePositionalSpec(cmd.positionalType)];
        }
        return [];
    }
    generateIndexedPositionalSpec(positional, index) {
        const name = this.escapeDescription(positional.name);
        const separator = positional.optional ? '::' : ':';
        switch (positional.type) {
            case 'change-id':
                return `'${index}${separator}${name}:_openspec_complete_changes'`;
            case 'spec-id':
                return `'${index}${separator}${name}:_openspec_complete_specs'`;
            case 'change-or-spec-id':
                return `'${index}${separator}${name}:_openspec_complete_items'`;
            case 'schema-name':
                return `'${index}${separator}${name}:_openspec_complete_schemas'`;
            case 'path':
                return `'${index}${separator}${name}:_files'`;
            case 'shell':
                return `'${index}${separator}${name}:(zsh bash fish powershell)'`;
            default:
                return `'${index}${separator}${name}:'`;
        }
    }
    /**
     * Escape special characters in descriptions
     */
    escapeDescription(desc) {
        return desc
            .replace(/\\/g, '\\\\')
            .replace(/'/g, "\\'")
            .replace(/\[/g, '\\[')
            .replace(/]/g, '\\]')
            .replace(/:/g, '\\:');
    }
    /**
     * Escape special characters in values
     */
    escapeValue(value) {
        return value
            .replace(/\\/g, '\\\\')
            .replace(/'/g, "\\'")
            .replace(/ /g, '\\ ');
    }
    /**
     * Sanitize command names for use in function names
     */
    sanitizeFunctionName(name) {
        return name.replace(/-/g, '_');
    }
}
//# sourceMappingURL=zsh-generator.js.map