import type { Command } from 'commander';
import { mkdirSync, writeFileSync } from 'fs';
import { resolve } from 'path';
import { homedir } from 'os';

const SUBCOMMANDS = ['start', 'tui', 'send', 'sessions', 'doctor', 'config', 'setup', 'completion'];

const SUBCOMMAND_OPTIONS: Record<string, string[]> = {
  start: ['-c', '--config'],
  tui: ['-c', '--config', '-f', '--fullscreen'],
  send: ['-c', '--config', '--no-tools'],
  config: ['-c', '--config', '--raw'],
  setup: ['-c', '--config'],
  completion: ['--install'],
};

export function generateBashCompletion(): string {
  const subcmds = SUBCOMMANDS.join(' ');
  const cases = Object.entries(SUBCOMMAND_OPTIONS)
    .map(([cmd, opts]) => `      ${cmd}) COMPREPLY=( $(compgen -W "${opts.join(' ')}" -- "$cur") ) ;;`)
    .join('\n');

  return `# Flynn bash completion — generated by 'flynn completion bash'
_flynn_completions() {
  local cur prev subcmd
  cur="\${COMP_WORDS[COMP_CWORD]}"
  prev="\${COMP_WORDS[COMP_CWORD-1]}"

  if [[ \${COMP_CWORD} -eq 1 ]]; then
    COMPREPLY=( $(compgen -W "${subcmds} --help --version" -- "$cur") )
    return
  fi

  subcmd="\${COMP_WORDS[1]}"
  case "$subcmd" in
${cases}
      completion) COMPREPLY=( $(compgen -W "bash zsh fish --install" -- "$cur") ) ;;
      *) COMPREPLY=() ;;
  esac
}
complete -F _flynn_completions flynn
`;
}

export function generateZshCompletion(): string {
  const subcmds = SUBCOMMANDS.map(c => `'${c}:${c} subcommand'`).join(' ');
  const cases = Object.entries(SUBCOMMAND_OPTIONS)
    .map(([cmd, opts]) => {
      const flags = opts.filter(o => o.startsWith('--')).map(o => `'${o}'`).join(' ');
      return `    ${cmd}) compadd ${flags} ;;`;
    })
    .join('\n');

  return `#compdef flynn
# Flynn zsh completion — generated by 'flynn completion zsh'
_flynn() {
  local -a subcmds
  subcmds=(${subcmds})

  if (( CURRENT == 2 )); then
    _describe 'command' subcmds
    return
  fi

  case "\${words[2]}" in
${cases}
    completion) compadd bash zsh fish '--install' ;;
    *) ;;
  esac
}
compdef _flynn flynn
`;
}

export function generateFishCompletion(): string {
  const lines = [
    '# Flynn fish completion — generated by \'flynn completion fish\'',
    '# Disable file completions by default',
    'complete -c flynn -f',
    '',
    '# Subcommands',
  ];

  for (const cmd of SUBCOMMANDS) {
    lines.push(`complete -c flynn -n '__fish_use_subcommand' -a '${cmd}' -d '${cmd} subcommand'`);
  }
  lines.push('complete -c flynn -n \'__fish_use_subcommand\' -l help -d \'Show help\'');
  lines.push('complete -c flynn -n \'__fish_use_subcommand\' -l version -d \'Show version\'');
  lines.push('');
  lines.push('# Subcommand options');

  for (const [cmd, opts] of Object.entries(SUBCOMMAND_OPTIONS)) {
    for (const opt of opts) {
      const flag = opt.replace(/^-+/, '');
      const short = opt.startsWith('--') ? '' : ` -s ${flag}`;
      const long = opt.startsWith('--') ? ` -l ${flag}` : '';
      lines.push(`complete -c flynn -n '__fish_seen_subcommand_from ${cmd}'${short}${long}`);
    }
  }

  lines.push('complete -c flynn -n \'__fish_seen_subcommand_from completion\' -a \'bash zsh fish\' -d \'Shell type\'');
  lines.push('');

  return lines.join('\n');
}

function getInstallPath(shell: string): string {
  const home = homedir();
  switch (shell) {
    case 'bash': return resolve(home, '.local/share/bash-completion/completions/flynn');
    case 'zsh': return resolve(home, '.zfunc/_flynn');
    case 'fish': return resolve(home, '.config/fish/completions/flynn.fish');
    default: throw new Error(`Unknown shell: ${shell}`);
  }
}

export function registerCompletionCommand(program: Command): void {
  program
    .command('completion')
    .description('Generate shell completion script')
    .argument('<shell>', 'Shell type: bash, zsh, or fish')
    .option('--install', 'Install to standard location')
    .action((shell: string, opts: { install?: boolean }) => {
      const generators: Record<string, () => string> = {
        bash: generateBashCompletion,
        zsh: generateZshCompletion,
        fish: generateFishCompletion,
      };

      const generator = generators[shell];
      if (!generator) {
        console.error(`Unknown shell: ${shell}. Supported: bash, zsh, fish`);
        process.exit(1);
      }

      const script = generator();

      if (opts.install) {
        const installPath = getInstallPath(shell);
        mkdirSync(resolve(installPath, '..'), { recursive: true });
        writeFileSync(installPath, script, 'utf-8');
        console.log(`Completion script installed to: ${installPath}`);
        if (shell === 'zsh') {
          console.log('Ensure ~/.zfunc is in your fpath: fpath=(~/.zfunc $fpath)');
        }
      } else {
        process.stdout.write(script);
      }
    });
}
