/**
 * Windows shell quoting utilities for child_process.spawn().
 *
 * When spawn() is called with `shell: true` on Windows, the command and
 * arguments are concatenated and passed to cmd.exe. Paths containing spaces
 * must be wrapped in double-quotes to prevent cmd.exe from splitting them
 * into separate tokens.
 *
 * This module is intentionally dependency-free so it can be unit-tested
 * without mocking Electron.
 */
import path from 'path';

/**
 * Quote a path/value for safe use with Windows cmd.exe (shell: true in spawn).
 *
 * When Node.js spawn is called with `shell: true` on Windows, cmd.exe
 * interprets spaces as argument separators. Wrapping the value in double
 * quotes prevents this. On non-Windows platforms the value is returned
 * unchanged so this function can be called unconditionally.
 */
export function quoteForCmd(value: string): string {
  if (process.platform !== 'win32') return value;
  if (!value.includes(' ')) return value;
  if (value.startsWith('"') && value.endsWith('"')) return value;
  return `"${value}"`;
}

/**
 * Determine whether a spawn call needs `shell: true` on Windows.
 *
 * Full (absolute) paths can be executed directly by the OS via
 * CreateProcessW, which handles spaces correctly without a shell.
 * Simple command names (e.g. 'uv', 'node') need shell for PATH/PATHEXT
 * resolution on Windows.
 */
export function needsWinShell(bin: string): boolean {
  if (process.platform !== 'win32') return false;
  return !path.win32.isAbsolute(bin);
}

/**
 * Prepare command and args for spawn(), handling Windows paths with spaces.
 *
 * Returns the shell option, the (possibly quoted) command, and the
 * (possibly quoted) args array ready for child_process.spawn().
 */
export function prepareWinSpawn(
  command: string,
  args: string[],
  forceShell?: boolean,
): { shell: boolean; command: string; args: string[] } {
  const isWin = process.platform === 'win32';
  const useShell = forceShell ?? (isWin && !path.win32.isAbsolute(command));

  if (!useShell || !isWin) {
    return { shell: useShell, command, args };
  }

  return {
    shell: true,
    command: quoteForCmd(command),
    args: args.map(a => quoteForCmd(a)),
  };
}

/**
 * Normalize a module path for NODE_OPTIONS `--require` usage.
 *
 * Node parses NODE_OPTIONS using shell-like escaping rules. On Windows,
 * a quoted path with backslashes (e.g. "C:\Users\...") loses separators
 * because backslashes are interpreted as escapes. Using forward slashes
 * keeps the absolute path intact while still being valid on Windows.
 */
export function normalizeNodeRequirePathForNodeOptions(modulePath: string): string {
  if (process.platform !== 'win32') return modulePath;
  return modulePath.replace(/\\/g, '/');
}

/**
 * Append a `--require` preload module path to NODE_OPTIONS safely.
 */
export function appendNodeRequireToNodeOptions(
  nodeOptions: string | undefined,
  modulePath: string,
): string {
  const normalized = normalizeNodeRequirePathForNodeOptions(modulePath);
  return `${nodeOptions ?? ''} --require "${normalized}"`.trim();
}
