#!/usr/bin/env node

/**
 * @license
 * Copyright 2025 Qwen Code
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * Production bin entry wrapper.
 *
 * For most commands: launches the bundled CLI with --expose-gc so that
 * global.gc() is available for the memory-pressure monitor's critical-tier
 * cleanup.
 *
 * For bootstrap fast paths: imports cli.js directly in-process, skipping the
 * spawnSync overhead. These paths do not need global.gc(); the normal
 * interactive path still relaunches with --expose-gc for the memory-pressure
 * monitor.
 */

const relaunchArgs = process.env['QWEN_CODE_RELAUNCH_ARGS'];
let cliArgs = process.argv.slice(2);
try {
  cliArgs = relaunchArgs ? JSON.parse(relaunchArgs) : cliArgs;
} catch {
  // Ignore stale or user-provided junk; normal argv is still usable.
}
delete process.env['QWEN_CODE_RELAUNCH_ARGS'];
delete process.env['QWEN_CODE_PENDING_COMPILE_CACHE'];

function hasFlag(flag, alias) {
  for (const arg of cliArgs) {
    if (arg === '--') {
      return false;
    }
    if (arg === flag || arg === alias) {
      return true;
    }
  }
  return false;
}

function isInProcessFastPath() {
  const first = cliArgs[0];
  if (first === 'serve' || first === 'mcp') {
    return true;
  }
  if (first === undefined || first.startsWith('-')) {
    return hasFlag('--help', '-h') || hasFlag('--version', '-v');
  }
  return false;
}

const isTopLevelVersion =
  (cliArgs[0] === undefined || cliArgs[0].startsWith('-')) &&
  hasFlag('--version', '-v');

if (isTopLevelVersion && process.env['CLI_VERSION']) {
  process.stdout.write(`${process.env['CLI_VERSION']}\n`);
  process.exit(0);
}

const { existsSync, readFileSync, realpathSync, statSync } = await import(
  'node:fs'
);
const { createHash } = await import('node:crypto');
const { homedir, tmpdir } = await import('node:os');
const { parseEnv } = await import('node:util');
const { fileURLToPath, pathToFileURL } = await import('node:url');
const { delimiter, dirname, join, parse, resolve, sep } = await import(
  'node:path'
);

const __dirname = dirname(fileURLToPath(import.meta.url));
const currentEntryPath = realpathSync(fileURLToPath(import.meta.url));

function getHomeDir() {
  try {
    return homedir() || tmpdir();
  } catch {
    return tmpdir();
  }
}

function resolveQwenHome() {
  const configured = process.env['QWEN_HOME'];
  if (!configured) return join(getHomeDir(), '.qwen');
  if (configured === '~') return getHomeDir();
  if (configured.startsWith('~/') || configured.startsWith('~\\')) {
    return join(
      getHomeDir(),
      ...configured
        .slice(2)
        .split(/[/\\]+/)
        .filter(Boolean),
    );
  }
  return resolve(configured);
}

function preResolveQwenHome() {
  if (Object.hasOwn(process.env, 'QWEN_HOME')) return;
  const home = getHomeDir();
  for (const candidate of [join(home, '.qwen', '.env'), join(home, '.env')]) {
    try {
      const source = readFileSync(candidate, 'utf8')
        .replace(/^\uFEFF/, '')
        .replace(/^(\s*(?:export\s+)?QWEN_HOME):[^\S\r\n]+/gm, '$1=');
      const configured = parseEnv(source)['QWEN_HOME'];
      if (configured) {
        process.env['QWEN_HOME'] = configured;
        return;
      }
    } catch {
      // Match the CLI's quiet handling of missing or invalid home env files.
    }
  }
}

delete process.env['QWEN_CODE_MANAGED_NPM_UPDATE'];
preResolveQwenHome();

function getManagedNpmPin() {
  try {
    const pin = JSON.parse(process.env['QWEN_CODE_MANAGED_NPM_PIN'] ?? '');
    if (pin.bootstrap !== currentEntryPath) return undefined;
    if (
      typeof pin.updateRoot !== 'string' ||
      resolve(pin.updateRoot) !== pin.updateRoot
    ) {
      return undefined;
    }
    if (pin.version === null) {
      return { version: null, updateRoot: pin.updateRoot };
    }
    return typeof pin.version === 'string' &&
      /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(
        pin.version,
      )
      ? { version: pin.version, updateRoot: pin.updateRoot }
      : undefined;
  } catch {
    return undefined;
  }
}

const managedNpmPin = getManagedNpmPin();
const managedNpmUpdateRoot =
  managedNpmPin?.updateRoot ?? join(resolveQwenHome(), 'updates', 'npm');

function getManagedNpmInstallation() {
  try {
    if (managedNpmPin?.version === null) return undefined;
    const launcherRoot = join(
      managedNpmUpdateRoot,
      createHash('sha256').update(currentEntryPath).digest('hex').slice(0, 16),
    );
    let version = managedNpmPin?.version;
    if (version === undefined) {
      const active = JSON.parse(
        readFileSync(join(launcherRoot, 'active.json'), 'utf8'),
      );
      const basePackageJsonPath = [
        join(__dirname, 'package.json'),
        join(__dirname, '..', 'package.json'),
      ].find((candidate) => existsSync(candidate));
      if (!basePackageJsonPath) return undefined;
      const basePackage = JSON.parse(readFileSync(basePackageJsonPath, 'utf8'));
      if (
        typeof active.version !== 'string' ||
        !/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(
          active.version,
        ) ||
        typeof active.bootstrap !== 'string' ||
        realpathSync(active.bootstrap) !== currentEntryPath ||
        active.baseVersion !== basePackage.version ||
        active.bootstrapCtimeMs !== statSync(currentEntryPath).ctimeMs
      ) {
        return undefined;
      }
      version = active.version;
    }
    const packageRoot = join(
      launcherRoot,
      'versions',
      version,
      'node_modules',
      '@qwen-code',
      'qwen-code',
    );
    const packageJsonPath = join(packageRoot, 'package.json');
    const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
    const cliPath = join(packageRoot, 'cli.js');
    if (
      pkg.name !== '@qwen-code/qwen-code' ||
      pkg.version !== version ||
      !existsSync(cliPath)
    ) {
      return undefined;
    }
    process.env['QWEN_CODE_MANAGED_NPM_UPDATE'] = 'true';
    return { cliPath, packageJsonPath, version };
  } catch {
    return undefined;
  }
}

// The entry a subprocess should call to reach THIS build.
//
// A skill that shells out to `qwen …` gets whatever `qwen` PATH resolves to, which
// is not necessarily the code that launched it: with an older global install on the
// machine, a current-source daemon's `qwen review agent-prompt --role 0` landed in a
// v0.19.10 binary whose `agent-prompt` predates `--role`, and the run died on
// "Missing required argument: chunk". This file is the executable entry and the one
// thing that knows its own path, so it publishes it; `getShellContextEnvVars` passes
// it to every shell subprocess, and a caller prefers it over a bare `qwen`.
//
// Assignment, not `||=`: an inherited value is another session's CLI — an outer
// qwen shelling out to this one — and honouring it re-creates the exact skew above,
// one level up. Each entry stamps itself, so nested sessions each call their own
// build. The managed-version pin keeps nested calls on the running session's build
// even if a background update changes the active pointer. A post-update relaunch
// clears that pin so the launcher's wrapper selects the newly active build.
//
// One exception, and it points the SAME way: the standalone package launches this
// file through a shim (`bin/qwen`) that selects the BUNDLED Node — the host may
// have none — and announces itself via QWEN_CODE_LAUNCHER_PATH. There, "the entry
// that reaches this build" is the shim: stamping this file instead would hand
// subprocesses a `#!/usr/bin/env node` script on a machine where that resolves to
// nothing. Read before the spawn path deletes the variable below.
// Captured AND deleted here, not just read: the serve/mcp fast path below never
// reaches the spawn branch that used to delete it, so the hint leaked into every
// child of a standalone daemon — and a child qwen from a DIFFERENT checkout
// would read the outer shim and republish it as its own entry: the wrong build,
// wearing this one's stamp.
const standaloneShim = process.env['QWEN_CODE_LAUNCHER_PATH'];
delete process.env['QWEN_CODE_LAUNCHER_PATH'];

const managedNpmInstallation = getManagedNpmInstallation();
const validStandaloneShim =
  standaloneShim && existsSync(standaloneShim) ? standaloneShim : undefined;
process.env['QWEN_CODE_CLI'] =
  validStandaloneShim ?? fileURLToPath(import.meta.url);
if (validStandaloneShim) {
  delete process.env['QWEN_CODE_MANAGED_NPM_PIN'];
  delete process.env['QWEN_CODE_MANAGED_NPM_ROOT'];
} else {
  process.env['QWEN_CODE_MANAGED_NPM_ROOT'] = managedNpmUpdateRoot;
  process.env['QWEN_CODE_MANAGED_NPM_PIN'] = JSON.stringify({
    bootstrap: currentEntryPath,
    version: managedNpmInstallation?.version ?? null,
    updateRoot: managedNpmUpdateRoot,
  });
}
const cliPathCandidates = [
  managedNpmInstallation?.cliPath,
  join(__dirname, 'cli.js'),
  join(__dirname, '..', 'dist', 'cli.js'),
].filter(Boolean);
const packageJsonPathCandidates = [
  managedNpmInstallation?.packageJsonPath,
  join(__dirname, 'package.json'),
  join(__dirname, '..', 'package.json'),
].filter(Boolean);
const cliPath =
  cliPathCandidates.find((candidate) => existsSync(candidate)) ??
  cliPathCandidates[0];
const packageJsonPath =
  packageJsonPathCandidates.find((candidate) => existsSync(candidate)) ??
  packageJsonPathCandidates[0];

if (isTopLevelVersion) {
  try {
    const { readFileSync } = await import('node:fs');
    const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
    process.stdout.write(`${pkg.version || 'unknown'}\n`);
    process.exit(0);
  } catch {
    // Fall through to cli.js, which has its own version fallback.
  }
}

if (isInProcessFastPath()) {
  const { default: module } = await import('node:module');
  const compileCache = module.enableCompileCache?.();
  if (
    cliArgs[0] === 'serve' &&
    !process.env['NODE_COMPILE_CACHE'] &&
    compileCache?.status === module.constants?.compileCacheStatus?.ENABLED &&
    compileCache?.directory
  ) {
    process.env['QWEN_CODE_PENDING_COMPILE_CACHE'] = compileCache.directory;
  }
  process.argv[1] = cliPath;
  await import(pathToFileURL(cliPath).href);
} else {
  const { spawnSync } = await import('node:child_process');
  const UPDATE_COMPLETE_EXIT_CODE = 44;
  const launcherNames =
    process.platform === 'win32' ? ['qwen.cmd', 'qwen.exe', 'qwen'] : ['qwen'];
  const entryPath = resolve(process.argv[1]);
  const entryRootLength = parse(entryPath).root.length;
  const launcherFromEnv = standaloneShim;
  delete process.env['QWEN_CODE_LAUNCHER_PID'];
  const launcherCandidates = process.env['PATH']
    ?.split(delimiter)
    .flatMap((dir) => launcherNames.map((name) => join(dir, name)))
    .filter((candidate) => existsSync(candidate));
  const launcher =
    launcherFromEnv && existsSync(launcherFromEnv)
      ? launcherFromEnv
      : launcherCandidates
          ?.map((candidate) => {
            if (resolve(candidate) === entryPath) {
              return { candidate, score: Number.MAX_SAFE_INTEGER };
            }
            try {
              if (realpathSync(candidate) === realpathSync(entryPath)) {
                return { candidate, score: Number.MAX_SAFE_INTEGER };
              }
            } catch {
              // Fall back to matching the installation prefix.
            }
            let parent = resolve(dirname(candidate));
            while (
              parent.length > entryRootLength &&
              entryPath !== parent &&
              !entryPath.startsWith(`${parent}${sep}`)
            ) {
              const next = dirname(parent);
              if (next === parent) break;
              parent = next;
            }
            return { candidate, score: parent.length };
          })
          .filter(({ score }) => score > entryRootLength)
          .sort((a, b) => b.score - a.score)[0]?.candidate;
  const env = {
    ...process.env,
    QWEN_CODE_LAUNCHER_PID: String(process.pid),
  };
  const result = spawnSync(
    process.execPath,
    ['--expose-gc', cliPath, ...cliArgs],
    { stdio: 'inherit', env },
  );

  if (result.signal) {
    process.kill(process.pid, result.signal);
  } else if (result.status !== UPDATE_COMPLETE_EXIT_CODE) {
    process.exit(result.status ?? 1);
  } else {
    if (!launcher) {
      process.stderr.write(
        'Update successful! The new version will be used on your next run.\n',
      );
      process.exit(0);
    }
    const relaunchEnv = {
      ...process.env,
      QWEN_CODE_RELAUNCH_ARGS: JSON.stringify(cliArgs),
      QWEN_CODE_SKIP_UPDATE_CHECK_ONCE: 'true',
    };
    delete relaunchEnv['QWEN_CODE_MANAGED_NPM_PIN'];
    const relaunchResult =
      process.platform === 'win32' && launcher.endsWith('.cmd')
        ? spawnSync(
            process.env['ComSpec'] ?? 'cmd.exe',
            ['/d', '/s', '/c', `""${launcher}""`],
            { stdio: 'inherit', env: relaunchEnv },
          )
        : spawnSync(launcher, [], {
            stdio: 'inherit',
            env: relaunchEnv,
          });
    if (relaunchResult.signal) {
      process.kill(process.pid, relaunchResult.signal);
    } else {
      process.exit(relaunchResult.status ?? 1);
    }
  }
}
