#!/usr/bin/env node

const { Command } = require('commander');
const kleur = require('kleur');
const pkg = require('../package.json');
const { runNew } = require('../lib/commands/new');
const { runDoctor } = require('../lib/commands/doctor');
const { runFeatures } = require('../lib/commands/features');
const { runValidate } = require('../lib/commands/validate');
const { runDeployCommand } = require('../lib/commands/deploy');
const { runCheck } = require('../lib/commands/check');
const { runRun } = require('../lib/commands/run');
const { runReset } = require('../lib/commands/reset');
const { runAdd } = require('../lib/commands/add');
const { runRemove } = require('../lib/commands/remove');
const { runUpdate } = require('../lib/commands/update');
const { runDocs } = require('../lib/commands/docs');
const { runNotificationsText } = require('../lib/commands/notifications');
const { runSplash } = require('../lib/commands/splash');
const { runIcon } = require('../lib/commands/icon');
const { runFavicon } = require('../lib/commands/favicon');
const {
  runConfigure: runIosConfigure,
  runBuild: runIosBuild,
  runRelease: runIosRelease,
  runClean: runIosClean,
} = require('../lib/commands/ios');
const {
  runConfigure: runCodemagicConfigure,
  runRelease: runCodemagicRelease,
  runStatus: runCodemagicStatus,
} = require('../lib/commands/codemagic');
const {
  createTranslator,
  normalizeLanguage,
  detectDefaultLanguage
} = require('../lib/utils/i18n');
const { getStoredLanguage, setStoredLanguage } = require('../lib/utils/license');
const { promptLanguage } = require('../lib/utils/prompts');
const { ensureLicenseKey, shouldRequireLicenseForArgv } = require('../lib/utils/license-gate');
const { checkForUpdates } = require('../lib/utils/updates');
const { printCompactHeader } = require('../lib/utils/brand');
const ui = require('../lib/utils/ui');
const { stripVerboseFlag, isVerbose, printVerboseError } = require('../lib/utils/debug');
const { formatError } = require('../lib/utils/friendly-error');

function createLocalizedHelpConfig(t) {
  return {
    formatHelp(cmd, helper) {
      const termWidth = helper.padWidth(cmd, helper);
      const helpWidth = helper.helpWidth || 80;
      const itemIndentWidth = 2;
      const itemSeparatorWidth = 2;
      const bulletIndentWidth = 4; // "  • "

      function formatItem(term, description, indentWidth) {
        const indent = indentWidth ?? itemIndentWidth;
        if (description) {
          const fullText = `${term.padEnd(termWidth + itemSeparatorWidth)}${description}`;
          return helper.wrap(
            fullText,
            helpWidth - indent,
            termWidth + itemSeparatorWidth
          );
        }

        return term;
      }

      function formatList(textArray) {
        return textArray.join('\n').replace(/^/gm, ' '.repeat(itemIndentWidth));
      }

      function formatBulletList(textArray) {
        return textArray
          .map((text) => {
            const lines = text.split('\n');
            return lines
              .map((line, i) => (i === 0 ? `  ${kleur.dim('•')} ${line}` : `    ${line}`))
              .join('\n');
          })
          .join('\n');
      }

      function localizeSubcommandTerm(term) {
        // Hide " [options]" entirely on the root help — users can run
        // `kasy <command> --help` to see options for a specific command.
        // Subcommand help still shows its own Options section.
        return term.replace(/ \[options\]/g, '');
      }

      const localizedUsage = helper.commandUsage(cmd).replace(
        / \[options\]/g,
        ` ${t('cli.help.inline.options')}`
      );
      let output = [`${t('cli.help.heading.usage')}: ${localizedUsage}`, ''];

      const commandDescription = helper.commandDescription(cmd);
      if (commandDescription.length > 0) {
        output = output.concat([helper.wrap(commandDescription, helpWidth, 0), '']);
      }

      const argumentList = helper.visibleArguments(cmd).map((argument) => {
        return formatItem(
          helper.argumentTerm(argument),
          helper.argumentDescription(argument)
        );
      });
      if (argumentList.length > 0) {
        output = output.concat([`${t('cli.help.heading.arguments')}:`, formatList(argumentList), '']);
      }

      const optionList = helper.visibleOptions(cmd).map((option) => {
        return formatItem(helper.optionTerm(option), helper.optionDescription(option));
      });
      if (optionList.length > 0) {
        output = output.concat([`${t('cli.help.heading.options')}:`, formatList(optionList), '']);
      }

      if (this.showGlobalOptions) {
        const globalOptionList = helper.visibleGlobalOptions(cmd).map((option) => {
          return formatItem(helper.optionTerm(option), helper.optionDescription(option));
        });
        if (globalOptionList.length > 0) {
          output = output.concat([
            `${t('cli.help.heading.globalOptions')}:`,
            formatList(globalOptionList),
            ''
          ]);
        }
      }

      const visibleCommands = helper.visibleCommands(cmd);
      if (visibleCommands.length > 0) {
        const isRoot = cmd.parent === null || cmd.parent === undefined;
        if (isRoot) {
          // Group root commands by intent for easier scanning by non-devs.
          const groups = [
            { id: 'start',       ids: ['new', 'doctor', 'features'] },
            { id: 'work',        ids: ['add', 'remove', 'update', 'run', 'reset', 'splash', 'icon', 'favicon', 'notifications'] },
            { id: 'publish',     ids: ['deploy', 'check', 'ios', 'codemagic'] },
            { id: 'maintenance', ids: ['upgrade', 'version', 'uninstall', 'docs'] },
            { id: 'advanced',    ids: ['setup', 'validate'] },
          ];
          // Commander auto-generates a `help` subcommand. Hide it from the
          // "Other" section — the tip line at the bottom already teaches users
          // how to get per-command help.
          const HIDDEN_FROM_OTHER = new Set(['help']);
          const knownIds = new Set(groups.flatMap((g) => g.ids));
          const byName = new Map(visibleCommands.map((c) => [c.name(), c]));
          for (const group of groups) {
            const items = group.ids
              .map((id) => byName.get(id))
              .filter(Boolean)
              .map((sub) =>
                formatItem(
                  localizeSubcommandTerm(helper.subcommandTerm(sub)),
                  helper.subcommandDescription(sub),
                  bulletIndentWidth
                )
              );
            if (items.length === 0) continue;
            output = output.concat([
              kleur.cyan().bold(t(`cli.help.group.${group.id}`)),
              formatBulletList(items),
              ''
            ]);
          }
          const otherItems = visibleCommands
            .filter((c) => !knownIds.has(c.name()) && !HIDDEN_FROM_OTHER.has(c.name()))
            .map((sub) =>
              formatItem(
                localizeSubcommandTerm(helper.subcommandTerm(sub)),
                helper.subcommandDescription(sub),
                bulletIndentWidth
              )
            );
          if (otherItems.length > 0) {
            output = output.concat([
              kleur.cyan().bold(t('cli.help.group.other')),
              formatBulletList(otherItems),
              ''
            ]);
          }
          output = output.concat([kleur.dim(helper.wrap(t('cli.help.tip'), helpWidth, 0)), '']);
        } else {
          // Subcommand help — keep the flat list (no grouping).
          const commandList = visibleCommands.map((subcommand) =>
            formatItem(
              localizeSubcommandTerm(helper.subcommandTerm(subcommand)),
              helper.subcommandDescription(subcommand)
            )
          );
          output = output.concat([`${t('cli.help.heading.commands')}:`, formatList(commandList), '']);
        }
      }

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

function applyLocalizedHelp(command, t) {
  command
    .configureHelp(createLocalizedHelpConfig(t))
    .helpOption('-h, --help', t('cli.help.optionDescription'))
    .showHelpAfterError(t('cli.help.afterError'));

  return command;
}

function buildProgram(language) {
  const t = createTranslator(language);
  const program = applyLocalizedHelp(new Command(), t);

  const langOption = t('cli.option.lang');
  program
    .name('kasy')
    .description(t('cli.description'))
    .usage(t('cli.usage'))
    .version(pkg.version, '-V, --version', t('cli.option.version'))
    .option('-l, --lang <lang>', langOption);

  const helpParam = t('cli.command.help.paramName');
  program.helpCommand(`help [${helpParam}]`, t('cli.help.commandDescription'));
  const helpCommand = program._getHelpCommand();
  if (helpCommand) {
    applyLocalizedHelp(helpCommand, t);
  }

  program.addHelpText('beforeAll', `${kleur.bold().cyan(t('cli.tagline'))}\n`);
  program.addHelpText(
    'after',
    `${t('cli.help.quickStart')} ${kleur.cyan('kasy new')}\n`
  );

  applyLocalizedHelp(
    program
      .command('new')
      .argument('[directory]', 'Target folder (default: asks during setup)', '.')
      .option('-b, --backend <backend>', t('cli.command.setup.backendOption'))
      .option('--with <features>', t('cli.command.setup.featuresOption'))
      .option('--yes', 'Skip interactive questions — Quick mode with Starter preset')
      .option('-p, --project <id>', 'Firebase Project ID (used with --yes)')
      .description(t('cli.command.new.description'))
      .action(async (directory, options) => {
        await runNew(directory, { language, backend: options.backend, withModules: options.with, yes: options.yes, project: options.project });
      }),
    t
  );

  const directoryName = t('cli.command.setup.directoryName');
  const langName = t('cli.command.setup.langName');
  applyLocalizedHelp(
    program
      .command('setup', { hidden: true })
      .argument(`[${directoryName}]`, t('cli.command.setup.directoryArg'), '.')
      .option(`-l, --lang <${langName}>`, t('cli.command.setup.langOption'))
      .option('-b, --backend <backend>', t('cli.command.setup.backendOption'))
      .option('--with <features>', t('cli.command.setup.featuresOption'))
      .description(t('cli.command.setup.description'))
      .action(async (directory, options) => {
        // `setup` is an alias for `new` — unified flow.
        // Hidden from root help to reduce noise; still callable.
        await runNew(directory, {
          language: options.lang,
          backend: options.backend,
          withModules: options.with,
        });
      }),
    t
  );

  applyLocalizedHelp(
    program
      .command('doctor')
      .description(t('cli.command.doctor.description'))
      .action(async () => {
        await runDoctor({ language });
      }),
    t
  );

  applyLocalizedHelp(
    program
      .command('features')
      .description(t('cli.command.modules.description'))
      .action(() => {
        runFeatures({ language });
      }),
    t
  );

  applyLocalizedHelp(
    program
      .command('version')
      .description(t('cli.command.version.description'))
      .action(() => {
        console.log(pkg.version);
      }),
    t
  );

  applyLocalizedHelp(
    program
      .command('validate')
      .option('--analyze-only', t('cli.command.validate.analyzeOnlyOption'))
      .description(t('cli.command.validate.description'))
      .action(async (options) => {
        await runValidate({ language, analyzeOnly: Boolean(options.analyzeOnly) });
      }),
    t
  );

  applyLocalizedHelp(
    program
      .command('deploy')
      .argument('[directory]', 'Project folder (default: current directory)', '.')
      .option('-p, --project <id>', 'Firebase Project ID')
      .description(t('cli.command.deploy.description'))
      .action(async (directory, options) => {
        await runDeployCommand(directory, { project: options.project }, { language });
      }),
    t
  );

  applyLocalizedHelp(
    program
      .command('check')
      .argument('[directory]', 'Project folder (default: current directory)', '.')
      .option('--fix', 'Auto-fix missing configuration (generate FCM key, deploy missing functions)')
      .description(t('cli.command.check.description'))
      .action(async (directory, options) => {
        await runCheck({ directory: directory || '.', fix: Boolean(options.fix), language });
      }),
    t
  );

  applyLocalizedHelp(
    program
      .command('run')
      .argument('[directory]', 'Project folder (default: current directory)', '.')
      .option('--ios', 'Run on iOS simulator/device')
      .option('--android', 'Run on Android emulator/device')
      .option('--web', 'Run on Chrome (web)')
      .option('-d, --device <id>', 'Run on specific device ID')
      .option('--prod', 'Use production dart-defines (from launch.json)')
      .option('--no-defines', 'Skip dart-defines from launch.json')
      .option('--rc <mode>', 'RevenueCat key mode: auto (default — picks by device), test, or prod')
      .description(t('cli.command.run.description'))
      .action(async (directory, options) => {
        await runRun(directory, { language, ...options });
      }),
    t
  );

  applyLocalizedHelp(
    program
      .command('reset')
      .argument('[directory]', 'Project folder (default: current directory)', '.')
      .option('--ios', 'Reset on iOS simulator/device only')
      .option('--android', 'Reset on Android emulator/device only')
      .option('--web', 'Show web reset instructions only')
      .option('-d, --device <id>', 'Reset specific device ID')
      .option('--no-reinstall', 'Only uninstall, skip reinstall')
      .option('--no-clear-launcher', 'Android only: skip clearing the launcher cache (widget previews may stay gray)')
      .description(t('cli.command.reset.description'))
      .action(async (directory, options) => {
        await runReset(directory, { language, ...options });
      }),
    t
  );

  applyLocalizedHelp(
    program
      .command('add')
      .argument('[feature]', 'Feature to add (e.g. sentry, analytics, revenuecat, onboarding, llm_chat, ci...)')
      .option('--list', 'List all available features and their current status')
      .option('--yes', 'Skip interactive prompts (use placeholder values)')
      .option('-d, --directory <path>', 'Project folder (default: current directory)', '.')
      .description(t('cli.command.add.description'))
      .action(async (feature, options) => {
        await runAdd(feature, { language, ...options });
      }),
    t
  );

  applyLocalizedHelp(
    program
      .command('remove')
      .argument('[feature]', 'Feature to remove (e.g. sentry, analytics, llm_chat, ci...)')
      .option('--yes', 'Skip confirmation prompt')
      .option('-d, --directory <path>', 'Project folder (default: current directory)', '.')
      .description(t('cli.command.remove.description'))
      .action(async (feature, options) => {
        await runRemove(feature, { language, ...options });
      }),
    t
  );

  applyLocalizedHelp(
    program
      .command('update')
      .argument(
        '[feature]',
        t('cli.command.update.targetArg')
      )
      .option('--yes', 'Skip confirmation prompt')
      .option('-d, --directory <path>', 'Project folder (default: current directory)', '.')
      .description(t('cli.command.update.description'))
      .action(async (feature, options) => {
        await runUpdate(feature, { language, ...options });
      }),
    t
  );

  applyLocalizedHelp(
    program
      .command('upgrade')
      .description(t('cli.command.upgrade.description'))
      .action(() => {
        const { spawnSync } = require('node:child_process');
        printCompactHeader(t);
        console.log(kleur.cyan(t('cli.command.upgrade.running')) + '\n');
        const result = spawnSync('npm', ['install', '-g', 'kasy-cli'], { stdio: 'inherit', shell: true });
        if (result.status === 0) {
          console.log('\n' + kleur.green('✓ ' + t('cli.command.upgrade.done')) + '\n');
        } else {
          process.exitCode = result.status ?? 1;
        }
      }),
    t
  );

  applyLocalizedHelp(
    program
      .command('uninstall')
      .description(t('cli.command.uninstall.description'))
      .action(() => {
        const { spawnSync } = require('node:child_process');
        printCompactHeader(t);
        console.log(kleur.cyan(t('cli.command.uninstall.running')) + '\n');
        const result = spawnSync('npm', ['uninstall', '-g', 'kasy-cli'], { stdio: 'inherit', shell: true });
        if (result.status === 0) {
          console.log('\n' + kleur.green('✓ ' + t('cli.command.uninstall.done')) + '\n');
        } else {
          process.exitCode = result.status ?? 1;
        }
      }),
    t
  );

  const iosCmd = program
    .command('ios')
    .description(t('cli.command.ios.description'))
    .addHelpText('before', `\n${t('cli.command.ios.help.before')}`)
    .action(async () => {
      printCompactHeader(t);
      ui.intro(kleur.cyan(t('cli.command.ios.picker.intro')));
      const sub = await ui.select({
        message: t('cli.command.ios.picker.message'),
        options: [
          { value: 'configure', label: t('cli.command.ios.configure.description') },
          { value: 'release',   label: t('cli.command.ios.release.description') },
          { value: 'build',     label: t('cli.command.ios.build.description') },
          { value: 'clean',     label: t('cli.command.ios.clean.description') },
        ],
      });
      if (sub === 'configure') await runIosConfigure('.', { language });
      else if (sub === 'release') await runIosRelease('.', { language });
      else if (sub === 'build') await runIosBuild('.', { language });
      else if (sub === 'clean') await runIosClean('.', { language });
    });
  applyLocalizedHelp(
    iosCmd
      .command('configure')
      .argument('[directory]', 'Project folder (default: current directory)', '.')
      .description(t('cli.command.ios.configure.description'))
      .action(async (directory) => {
        await runIosConfigure(directory, { language });
      }),
    t
  );
  applyLocalizedHelp(
    iosCmd
      .command('release')
      .argument('[directory]', 'Project folder (default: current directory)', '.')
      .option('--no-bump', 'Do not increment build number in pubspec.yaml')
      .option('--version-name <version>', 'Set marketing version (e.g. 1.0.1)')
      .description(t('cli.command.ios.release.description'))
      .action(async (directory, options) => {
        await runIosRelease(directory, { language, noBump: Boolean(options.noBump), versionName: options.versionName });
      }),
    t
  );
  applyLocalizedHelp(
    iosCmd
      .command('build')
      .argument('[directory]', 'Project folder (default: current directory)', '.')
      .option('--no-bump', 'Do not increment build number in pubspec.yaml')
      .option('--version-name <version>', 'Set marketing version (e.g. 1.0.1)')
      .description(t('cli.command.ios.build.description'))
      .action(async (directory, options) => {
        await runIosBuild(directory, { language, noBump: Boolean(options.noBump), versionName: options.versionName });
      }),
    t
  );
  applyLocalizedHelp(
    iosCmd
      .command('clean')
      .argument('[directory]', 'Project folder (default: current directory)', '.')
      .description(t('cli.command.ios.clean.description'))
      .action(async (directory) => {
        await runIosClean(directory, { language });
      }),
    t
  );

  const codemagicCmd = program
    .command('codemagic')
    .description(t('cli.command.codemagic.description'))
    .addHelpText('before', `\n${t('cli.command.codemagic.help.before')}`)
    .action(async () => {
      printCompactHeader(t);
      ui.intro(kleur.cyan(t('cli.command.codemagic.picker.intro')));
      const sub = await ui.select({
        message: t('cli.command.codemagic.picker.message'),
        options: [
          { value: 'configure', label: t('cli.command.codemagic.configure.description') },
          { value: 'release',   label: t('cli.command.codemagic.release.description') },
          { value: 'status',    label: t('cli.command.codemagic.status.description'), hint: t('cli.command.codemagic.picker.statusHint') },
        ],
      });
      if (sub === 'configure') await runCodemagicConfigure('.', { language });
      else if (sub === 'release') await runCodemagicRelease('.', { language });
      else if (sub === 'status') {
        const buildId = await ui.text({
          message: 'Build ID',
          validate: (v) => (v && v.trim() ? undefined : 'Build ID is required'),
        });
        await runCodemagicStatus(buildId?.trim(), '.', { language });
      }
    });
  applyLocalizedHelp(
    codemagicCmd
      .command('configure')
      .argument('[directory]', 'Project folder (default: current directory)', '.')
      .description(t('cli.command.codemagic.configure.description'))
      .action(async (directory) => {
        await runCodemagicConfigure(directory, { language });
      }),
    t
  );
  applyLocalizedHelp(
    codemagicCmd
      .command('release')
      .argument('[directory]', 'Project folder (default: current directory)', '.')
      .description(t('cli.command.codemagic.release.description'))
      .action(async (directory) => {
        await runCodemagicRelease(directory, { language });
      }),
    t
  );
  applyLocalizedHelp(
    codemagicCmd
      .command('status')
      .argument('[buildId]', 'Codemagic build ID')
      .argument('[directory]', 'Project folder (default: current directory)', '.')
      .description(t('cli.command.codemagic.status.description'))
      .action(async (buildId, directory) => {
        await runCodemagicStatus(buildId, directory, { language });
      }),
    t
  );

  applyLocalizedHelp(
    program
      .command('docs')
      .description(t('cli.command.docs.description'))
      .action(async () => {
        await runDocs({ language });
      }),
    t
  );

  applyLocalizedHelp(
    program
      .command('splash')
      .argument('[directory]', 'Project folder (default: current directory)', '.')
      .requiredOption('--light <path>', 'PNG with dark logo (shown in light mode)')
      .requiredOption('--dark <path>', 'PNG with light logo (shown in dark mode)')
      .option('--skip-generate', 'Only copy files, do not run flutter_native_splash:create', false)
      .description(t('cli.command.splash.description'))
      .action(async (directory, options) => {
        const dir = directory || '.';
        await runSplash(dir, {
          language,
          light: options.light,
          dark: options.dark,
          skipGenerate: options.skipGenerate,
        });
      }),
    t
  );

  applyLocalizedHelp(
    program
      .command('icon')
      .argument('[directory]', 'Project folder (default: current directory)', '.')
      .requiredOption('--image <path>', 'PNG with the app icon (square, 1024x1024 recommended)')
      .option('--skip-generate', 'Only copy file, do not run flutter_launcher_icons', false)
      .description(t('cli.command.icon.description'))
      .action(async (directory, options) => {
        const dir = directory || '.';
        await runIcon(dir, {
          language,
          image: options.image,
          skipGenerate: options.skipGenerate,
        });
      }),
    t
  );

  applyLocalizedHelp(
    program
      .command('favicon')
      .argument('[directory]', 'Project folder (default: current directory)', '.')
      .requiredOption('--image <path>', 'PNG with the web favicon / PWA icon (square, 512x512+ recommended)')
      .option('--skip-generate', 'Only copy file, do not run flutter_launcher_icons', false)
      .description(t('cli.command.favicon.description'))
      .action(async (directory, options) => {
        const dir = directory || '.';
        await runFavicon(dir, {
          language,
          image: options.image,
          skipGenerate: options.skipGenerate,
        });
      }),
    t
  );

  const notificationsCmd = program
    .command('notifications')
    .description(t('cli.command.notifications.description'))
    .action(async () => {
      printCompactHeader(t);
      ui.intro(kleur.cyan(t('cli.command.notifications.picker.intro')));
      const sub = await ui.select({
        message: t('cli.command.notifications.picker.message'),
        options: [
          { value: 'text', label: t('cli.command.notifications.text.description') },
        ],
      });
      if (sub === 'text') await runNotificationsText('.', { language, directory: '.', lang: 'all' });
    });
  applyLocalizedHelp(
    notificationsCmd
      .command('text')
      .argument('[directory]', 'Project folder (default: current directory)', '.')
      .option('--locale <code>', 'i18n files to update: pt, en, es, or all (default: all)', 'all')
      .option('--demo-title <text>', 'Home → Features demo notification title')
      .option('--demo-body <text>', 'Home → Features demo card description / instant notification body')
      .option('--reminder-title <text>', 'Scheduled reminder notification title (Settings → Reminders)')
      .option('--reminder-body <text>', 'Scheduled reminder notification body')
      .description(t('cli.command.notifications.text.description'))
      .action(async (directory, options) => {
        const dir = directory || '.';
        await runNotificationsText(dir, {
          language,
          directory: dir,
          lang: options.locale,
          demoTitle: options.demoTitle,
          demoBody: options.demoBody,
          reminderTitle: options.reminderTitle,
          reminderBody: options.reminderBody,
        });
      }),
    t
  );

  return program;
}

function resolveLanguageFromArgv(argv) {
  for (let i = 0; i < argv.length; i += 1) {
    const arg = argv[i];

    if (arg === '--lang' || arg === '-l') {
      return normalizeLanguage(argv[i + 1]);
    }

    if (arg.startsWith('--lang=')) {
      return normalizeLanguage(arg.split('=')[1]);
    }
  }

  return null;
}

async function resolveLanguage(argv) {
  const fromArgv = resolveLanguageFromArgv(argv);
  if (fromArgv) return fromArgv;

  const fromEnv = normalizeLanguage(process.env.KASY_CLI_LANG);
  if (fromEnv) return fromEnv;

  const stored = getStoredLanguage();
  if (stored) return stored;

  if (process.stdin.isTTY) {
    const detected = detectDefaultLanguage();
    const t = createTranslator(detected);
    console.log('');
    console.log(kleur.bold().cyan(`  ${t('welcome.firstRun')}`));
    console.log(kleur.gray(`  ${t('welcome.chooseLanguage')}`));
    console.log('');
    const chosen = await promptLanguage(null);
    setStoredLanguage(chosen);
    return chosen;
  }

  return detectDefaultLanguage();
}

// Track the resolved language so the global catch can localize hints.
let activeLanguage = null;

async function main() {
  // Strip --verbose before commander sees it — that flag is handled out-of-band
  // by lib/utils/debug.js (reads process.argv directly).
  const argv = stripVerboseFlag(process.argv.slice(2));
  activeLanguage = await resolveLanguage(argv);
  if (shouldRequireLicenseForArgv(argv)) {
    await ensureLicenseKey({ language: activeLanguage, argv });
  }
  await checkForUpdates();
  const program = buildProgram(activeLanguage);
  await program.parseAsync([process.argv[0], process.argv[1], ...argv]);
}

main().catch((error) => {
  const t = activeLanguage ? createTranslator(activeLanguage) : null;
  console.error(formatError(error, t));
  printVerboseError(error);
  if (!isVerbose()) {
    console.error(kleur.dim('  Run again with --verbose (or set KASY_DEBUG=1) for full output.'));
  }
  process.exitCode = 1;
});
