#!/usr/bin/env node
import { execFile } from "node:child_process";
import { createHash, randomUUID } from "node:crypto";
import os from "node:os";
import path from "node:path";
import { fileURLToPath } from "node:url";
import {
  chmod,
  cp,
  lstat,
  mkdir,
  mkdtemp,
  readFile,
  readdir,
  readlink,
  realpath,
  rename,
  rm,
  symlink,
  writeFile
} from "node:fs/promises";
import { promisify } from "node:util";

const execFileAsync = promisify(execFile);
const sourceRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)));
const homeRoot = path.resolve(os.homedir());
const product = "Runrail Local Audit Runner";
const desktopProduct = "Runrail Desktop";
const distributionVersion = "2.4.14";
const installationStateName = "RUNRAIL_INSTALLATION.json";

if (process.argv.slice(2).some((argument) => argument === "--help" || argument === "-h")) {
  process.stdout.write(`${product} installer ${distributionVersion}\n\n`);
  process.stdout.write("Usage: node install.mjs\n");
  process.stdout.write("Installs or updates the verified local Runrail distribution and runs doctor.\n");
  process.stdout.write("Use --help or -h to show this message without changing the installation.\n");
  process.exit(0);
}

const {
  verifyCompatiblePriorRunrailDistribution,
  verifyRunrailDistribution
} = await import("./scripts/verify-runrail-distribution.mjs");
const {
  createRunrailPythonRuntimeManifest,
  verifyRunrailPythonRuntime
} = await import("./scripts/runrail-python-runtime-core.mjs");

function sha256(value) {
  return createHash("sha256").update(value).digest("hex");
}

function stableValue(value) {
  if (Array.isArray(value)) return value.map(stableValue);
  if (value && typeof value === "object") {
    return Object.fromEntries(Object.keys(value).sort().map((key) => [key, stableValue(value[key])]));
  }
  return value;
}

function stableJson(value) {
  return `${JSON.stringify(stableValue(value), null, 2)}\n`;
}

async function removeCommittedCleanupTarget(target, label, warnings) {
  if (!target) return;
  try {
    await rm(target, { recursive: true, force: true });
  } catch (error) {
    warnings.push({
      label,
      code: String(error?.code || "cleanup-failed")
    });
  }
}

function compareUtf8Names(left, right) {
  return Buffer.compare(Buffer.from(left, "utf8"), Buffer.from(right, "utf8"));
}

function defaultInstallBase() {
  if (process.platform === "win32") {
    return path.join(process.env.LOCALAPPDATA || path.join(homeRoot, "AppData", "Local"), "Runrail");
  }
  if (process.platform === "darwin") {
    return path.join(homeRoot, "Library", "Application Support", "Runrail");
  }
  return path.join(process.env.XDG_DATA_HOME || path.join(homeRoot, ".local", "share"), "runrail");
}

function defaultBinDir(installBase) {
  if (process.platform === "win32") return path.join(installBase, "bin");
  return path.join(homeRoot, ".local", "bin");
}

function defaultDesktopEntryDir() {
  if (process.platform === "win32") {
    return path.join(
      process.env.APPDATA || path.join(homeRoot, "AppData", "Roaming"),
      "Microsoft",
      "Windows",
      "Start Menu",
      "Programs"
    );
  }
  if (process.platform === "darwin") return path.join(homeRoot, "Applications");
  return path.join(process.env.XDG_DATA_HOME || path.join(homeRoot, ".local", "share"), "applications");
}

async function canonicalTarget(value) {
  const requested = path.resolve(value);
  const missingParts = [];
  let cursor = requested;
  while (true) {
    try {
      return path.join(await realpath(cursor), ...missingParts.reverse());
    } catch (error) {
      if (error?.code !== "ENOENT") throw error;
      const parent = path.dirname(cursor);
      if (parent === cursor) throw error;
      missingParts.push(path.basename(cursor));
      cursor = parent;
    }
  }
}

const canonicalSourceRoot = await canonicalTarget(sourceRoot);
const canonicalHomeRoot = await canonicalTarget(homeRoot);
const canonicalCwd = await canonicalTarget(process.cwd());

async function safeInstallRoot(value) {
  const resolved = await canonicalTarget(value);
  const filesystemRoot = path.parse(resolved).root;
  const relativeToSource = path.relative(canonicalSourceRoot, resolved);
  const insideSource = relativeToSource === "" || (
    relativeToSource !== ".." &&
    !relativeToSource.startsWith(`..${path.sep}`) &&
    !path.isAbsolute(relativeToSource)
  );
  if (
    resolved === filesystemRoot ||
    resolved === canonicalHomeRoot ||
    resolved === canonicalSourceRoot ||
    resolved === canonicalCwd ||
    resolved.length <= filesystemRoot.length + 2 ||
    insideSource
  ) {
    throw new Error(`Refusing unsafe Runrail install root: ${resolved}`);
  }
  return resolved;
}

async function exists(target) {
  try {
    return await lstat(target);
  } catch (error) {
    if (error?.code === "ENOENT") return null;
    throw error;
  }
}

function pathIdentity(value) {
  if (typeof value !== "string" || !value.trim()) return "";
  const resolved = path.resolve(value);
  return process.platform === "win32" ? resolved.toLowerCase() : resolved;
}

function samePath(left, right) {
  return pathIdentity(left) === pathIdentity(right);
}

async function ownedPathDigest(target, relative = ".") {
  const info = await lstat(target);
  if (info.isSymbolicLink()) {
    throw new Error(`Refusing a symlinked Runrail-owned path: ${target}`);
  }
  const digest = createHash("sha256");
  if (info.isDirectory()) {
    digest.update(`${relative}\0directory\0`);
    const entries = (await readdir(target)).sort((left, right) => compareUtf8Names(left, right));
    for (const name of entries) {
      digest.update(await ownedPathDigest(path.join(target, name), path.posix.join(relative, name)));
    }
  } else if (info.isFile()) {
    digest.update(`${relative}\0file\0`);
    digest.update(await readFile(target));
  } else {
    throw new Error(`Refusing an unsupported Runrail-owned path type: ${target}`);
  }
  return digest.digest();
}

async function ownedPathSha256(target) {
  return (await ownedPathDigest(target)).toString("hex");
}

function parsePythonVersion(value) {
  const match = String(value || "").match(/Python\s+(\d+)\.(\d+)/);
  if (!match) return null;
  return { major: Number(match[1]), minor: Number(match[2]) };
}

function supportedPython(value) {
  const version = parsePythonVersion(value);
  return Boolean(version && (version.major > 3 || (version.major === 3 && version.minor >= 11)));
}

async function probePython(command, prefixArgs = []) {
  try {
    const { stdout, stderr } = await execFileAsync(command, [...prefixArgs, "--version"], {
      timeout: 10_000,
      windowsHide: true
    });
    const version = `${stdout || ""}${stderr || ""}`.trim();
    return supportedPython(version) ? { command, prefixArgs, version } : null;
  } catch {
    return null;
  }
}

async function resolveBootstrapPython() {
  const configured = String(process.env.RUNRAIL_PYTHON_BOOTSTRAP || "").trim();
  const candidates = configured
    ? [[configured, []]]
    : process.platform === "win32"
      ? [["py", ["-3.13"]], ["py", ["-3.12"]], ["py", ["-3.11"]], ["python", []], ["python3", []]]
      : [["python3", []], ["python", []]];
  for (const [command, prefixArgs] of candidates) {
    const result = await probePython(command, prefixArgs);
    if (result) return result;
  }
  throw new Error("Runrail requires Python 3.11 or newer with venv support.");
}

function shellQuote(value) {
  return `'${String(value).replaceAll("'", "'\"'\"'")}'`;
}

function powershellQuote(value) {
  return `'${String(value).replaceAll("'", "''")}'`;
}

function cmdValue(value) {
  return String(value).replaceAll("%", "%%");
}

function unixLauncherContent(launcher, args = []) {
  const launcherArgs = [launcher, ...args].map(shellQuote).join(" ");
  return [
    "#!/bin/sh",
    `RUNRAIL_PINNED_NODE=${shellQuote(process.execPath)}`,
    'if [ -x "$RUNRAIL_PINNED_NODE" ]; then',
    `  exec "$RUNRAIL_PINNED_NODE" ${launcherArgs} "$@"`,
    "fi",
    `exec node ${launcherArgs} "$@"`,
    ""
  ].join("\n");
}

function windowsCmdLauncherContent(launcher, args = []) {
  const launcherArgs = [`"${cmdValue(launcher)}"`, ...args].join(" ");
  return [
    "@echo off",
    `set "RUNRAIL_PINNED_NODE=${cmdValue(process.execPath)}"`,
    'if exist "%RUNRAIL_PINNED_NODE%" (',
    `  "%RUNRAIL_PINNED_NODE%" ${launcherArgs} %*`,
    ") else (",
    `  node ${launcherArgs} %*`,
    ")",
    "exit /b %ERRORLEVEL%",
    ""
  ].join("\r\n");
}

function windowsPowerShellLauncherContent(launcher, args = []) {
  const launcherArgs = args.map((arg) => powershellQuote(arg)).join(" ");
  return [
    `$nodePath = ${powershellQuote(process.execPath)}`,
    "if (-not (Test-Path -LiteralPath $nodePath -PathType Leaf)) {",
    "  $nodePath = (Get-Command node -CommandType Application -ErrorAction Stop).Source",
    "}",
    `& $nodePath ${powershellQuote(launcher)}${launcherArgs ? ` ${launcherArgs}` : ""} @args`,
    "exit $LASTEXITCODE",
    ""
  ].join("\r\n");
}

function launcherDefinitions(binDir, releaseDir) {
  const launcher = path.join(releaseDir, "bin", "runrail.mjs");
  if (process.platform === "win32") {
    return [
      {
        path: path.join(binDir, "runrail.cmd"),
        content: windowsCmdLauncherContent(launcher)
      },
      {
        path: path.join(binDir, "runrail.ps1"),
        content: windowsPowerShellLauncherContent(launcher)
      },
      {
        path: path.join(binDir, "runrail-desktop.cmd"),
        content: windowsCmdLauncherContent(launcher, ["desktop"])
      },
      {
        path: path.join(binDir, "runrail-desktop.ps1"),
        content: windowsPowerShellLauncherContent(launcher, ["desktop"])
      }
    ];
  }
  return [
    {
      path: path.join(binDir, "runrail"),
      content: unixLauncherContent(launcher)
    },
    {
      path: path.join(binDir, "runrail-desktop"),
      content: unixLauncherContent(launcher, ["desktop"])
    }
  ];
}

async function writeLaunchers(binDir, releaseDir) {
  await mkdir(binDir, { recursive: true });
  const definitions = launcherDefinitions(binDir, releaseDir);
  for (const definition of definitions) {
    await writeFile(definition.path, definition.content, "utf8");
    if (process.platform !== "win32") await chmod(definition.path, 0o755);
  }
  return definitions.map((definition) => definition.path);
}

async function requireOwnedEntry(target, markerPath) {
  const targetInfo = await exists(target);
  const markerInfo = await exists(markerPath);
  if (!targetInfo) {
    if (markerInfo) throw new Error(`Refusing an orphaned desktop ownership marker: ${markerPath}`);
    return;
  }
  const expectedTargetType = process.platform === "darwin" ? "directory" : "file";
  if (
    targetInfo.isSymbolicLink() ||
    (expectedTargetType === "directory" && !targetInfo.isDirectory()) ||
    (expectedTargetType === "file" && !targetInfo.isFile())
  ) {
    throw new Error(`Refusing to replace an unsafe desktop entry: ${target}`);
  }
  if (!markerInfo?.isFile() || markerInfo.isSymbolicLink()) {
    throw new Error(`Refusing to replace an unrecognized desktop entry: ${target}`);
  }
  try {
    const marker = JSON.parse(await readFile(markerPath, "utf8"));
    if (marker.product !== desktopProduct || marker.managed !== true) throw new Error("invalid marker");
  } catch {
    throw new Error(`Refusing to replace a desktop entry with an invalid ownership marker: ${target}`);
  }
}

function desktopEntryPaths(entryDir) {
  if (process.platform === "win32") {
    return {
      target: path.join(entryDir, "Runrail Desktop.lnk"),
      marker: path.join(entryDir, "Runrail Desktop.runrail.json")
    };
  }
  if (process.platform === "darwin") {
    const target = path.join(entryDir, "Runrail Desktop.app");
    return {
      target,
      marker: path.join(target, "Contents", "Resources", "RUNRAIL_DESKTOP_APP.json")
    };
  }
  return {
    target: path.join(entryDir, "runrail-desktop.desktop"),
    marker: path.join(entryDir, "runrail-desktop.runrail.json")
  };
}

function desktopOwnershipMarker(installBase, currentPath, version = distributionVersion) {
  return {
    schemaVersion: 1,
    artifactType: "runrail-native-desktop-entry",
    product: desktopProduct,
    managed: true,
    version,
    installBase,
    currentPath
  };
}

async function requireExpectedDesktopOwnershipMarker(
  markerPath,
  installBase,
  currentPath,
  label,
  version = distributionVersion
) {
  let marker;
  try {
    marker = JSON.parse(await readFile(markerPath, "utf8"));
  } catch {
    throw new Error(`Refusing an invalid ${label} ownership marker: ${markerPath}`);
  }
  if (stableJson(marker) !== stableJson(desktopOwnershipMarker(installBase, currentPath, version))) {
    throw new Error(`Refusing a tampered ${label} ownership marker: ${markerPath}`);
  }
  return marker;
}

function desktopExecQuote(value) {
  return `"${String(value).replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"`;
}

function pathIsInside(parent, child) {
  const relative = path.relative(parent, child);
  return relative === "" || (
    relative !== ".." &&
    !relative.startsWith(`..${path.sep}`) &&
    !path.isAbsolute(relative)
  );
}

async function backupDesktopEntry(entry, installBase) {
  const backupRoot = await mkdtemp(path.join(installBase, ".desktop-entry-backup-"));
  const targetInfo = await exists(entry.target);
  const markerIsInsideTarget = pathIsInside(entry.target, entry.marker);
  const markerInfo = markerIsInsideTarget ? null : await exists(entry.marker);
  if (targetInfo) {
    await cp(entry.target, path.join(backupRoot, "target"), { recursive: targetInfo.isDirectory() });
  }
  if (markerInfo) await cp(entry.marker, path.join(backupRoot, "marker"));
  return {
    backupRoot,
    entry,
    hadTarget: Boolean(targetInfo),
    hadExternalMarker: Boolean(markerInfo),
    markerIsInsideTarget
  };
}

async function restoreDesktopEntry(backup) {
  await rm(backup.entry.target, { recursive: true, force: true });
  if (!backup.markerIsInsideTarget) await rm(backup.entry.marker, { force: true });
  if (backup.hadTarget) {
    const targetBackup = path.join(backup.backupRoot, "target");
    const targetBackupInfo = await lstat(targetBackup);
    await cp(targetBackup, backup.entry.target, { recursive: targetBackupInfo.isDirectory() });
  }
  if (backup.hadExternalMarker) {
    await cp(path.join(backup.backupRoot, "marker"), backup.entry.marker);
  }
  await rm(backup.backupRoot, { recursive: true, force: true });
}

async function writeDesktopEntry(entryDir, currentPath, workspacePath, installBase, binDir) {
  await mkdir(entryDir, { recursive: true });
  const desktopLauncher = path.join(
    binDir,
    process.platform === "win32" ? "runrail-desktop.cmd" : "runrail-desktop"
  );
  const icon = path.join(currentPath, "desktop", "icon-512.png");
  const ownershipMarker = desktopOwnershipMarker(installBase, currentPath);

  if (process.platform === "win32") {
    const { target: shortcutPath, marker: markerPath } = desktopEntryPaths(entryDir);
    await requireOwnedEntry(shortcutPath, markerPath);
    await rm(shortcutPath, { force: true });
    await rm(markerPath, { force: true });
    const powerShell = [
      "$shell = New-Object -ComObject WScript.Shell",
      "$shortcut = $shell.CreateShortcut($env:RUNRAIL_SHORTCUT_PATH)",
      "$shortcut.TargetPath = $env:RUNRAIL_DESKTOP_LAUNCHER",
      "$shortcut.WorkingDirectory = $env:RUNRAIL_WORKSPACE_PATH",
      "$shortcut.IconLocation = $env:RUNRAIL_ICON_PATH",
      "$shortcut.WindowStyle = 7",
      "$shortcut.Save()"
    ].join("; ");
    await execFileAsync("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", powerShell], {
      env: {
        ...process.env,
        RUNRAIL_SHORTCUT_PATH: shortcutPath,
        RUNRAIL_DESKTOP_LAUNCHER: desktopLauncher,
        RUNRAIL_WORKSPACE_PATH: workspacePath,
        RUNRAIL_ICON_PATH: icon
      },
      timeout: 30_000,
      windowsHide: true
    });
    await writeFile(
      markerPath,
      stableJson(ownershipMarker),
      "utf8"
    );
    return { kind: "windows-start-menu", path: shortcutPath, markerPath };
  }

  if (process.platform === "darwin") {
    const { target: appPath, marker: markerPath } = desktopEntryPaths(entryDir);
    await requireOwnedEntry(appPath, markerPath);
    await rm(appPath, { recursive: true, force: true });
    const executableDir = path.join(appPath, "Contents", "MacOS");
    const resourcesDir = path.join(appPath, "Contents", "Resources");
    await mkdir(executableDir, { recursive: true });
    await mkdir(resourcesDir, { recursive: true });
    const executablePath = path.join(executableDir, "Runrail Desktop");
    await writeFile(executablePath, `#!/bin/sh\nexec ${shellQuote(desktopLauncher)}\n`, "utf8");
    await chmod(executablePath, 0o755);
    await cp(icon, path.join(resourcesDir, "icon.png"));
    await writeFile(
      path.join(appPath, "Contents", "Info.plist"),
      `<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist version="1.0"><dict><key>CFBundleDevelopmentRegion</key><string>en</string><key>CFBundleDisplayName</key><string>Runrail Desktop</string><key>CFBundleExecutable</key><string>Runrail Desktop</string><key>CFBundleIdentifier</key><string>com.veyact.runrail.desktop</string><key>CFBundleIconFile</key><string>icon.png</string><key>CFBundleInfoDictionaryVersion</key><string>6.0</string><key>CFBundleName</key><string>Runrail Desktop</string><key>CFBundlePackageType</key><string>APPL</string><key>CFBundleShortVersionString</key><string>2.4.14</string><key>LSMinimumSystemVersion</key><string>12.0</string><key>NSHighResolutionCapable</key><true/></dict></plist>\n`,
      "utf8"
    );
    await writeFile(
      markerPath,
      stableJson(ownershipMarker),
      "utf8"
    );
    return { kind: "macos-application", path: appPath, markerPath };
  }

  const { target: desktopPath, marker: markerPath } = desktopEntryPaths(entryDir);
  await requireOwnedEntry(desktopPath, markerPath);
  await rm(desktopPath, { force: true });
  await rm(markerPath, { force: true });
  await writeFile(
    desktopPath,
    `[Desktop Entry]\nType=Application\nVersion=1.0\nName=Runrail Desktop\nComment=Local candidate-branch review workbench\nExec=${desktopExecQuote(desktopLauncher)}\nIcon=${icon}\nTerminal=false\nCategories=Development;Utility;\nStartupNotify=true\nX-Runrail-Managed=true\n`,
    "utf8"
  );
  await chmod(desktopPath, 0o755);
  await writeFile(
    markerPath,
    stableJson(ownershipMarker),
    "utf8"
  );
  return { kind: "linux-desktop-entry", path: desktopPath, markerPath };
}

function desktopLauncherKind() {
  if (process.platform === "win32") return "windows-start-menu";
  if (process.platform === "darwin") return "macos-application";
  return "linux-desktop-entry";
}

async function requireCurrentPointer(currentPath, releaseDir) {
  const currentInfo = await exists(currentPath);
  if (!currentInfo?.isSymbolicLink()) {
    throw new Error(`Refusing an unowned or tampered Runrail current pointer: ${currentPath}`);
  }
  const [currentTarget, releaseTarget] = await Promise.all([realpath(currentPath), realpath(releaseDir)]);
  if (!samePath(currentTarget, releaseTarget)) {
    throw new Error(`Refusing a Runrail current pointer with an unexpected target: ${currentPath}`);
  }
}

async function buildInstallationState({
  installBase,
  releaseDir,
  currentPath,
  binDir,
  launchers,
  desktopEntryDir,
  desktopLauncher,
  pythonRuntime
}) {
  const body = {
    schemaVersion: 1,
    artifactType: "runrail-installation-ownership",
    product,
    managed: true,
    version: distributionVersion,
    platform: process.platform,
    installBase,
    releaseDir,
    currentPath,
    binDir,
    launchers: await Promise.all(
      launchers.map(async (launcherPath) => ({
        path: launcherPath,
        sha256: await ownedPathSha256(launcherPath)
      }))
    ),
    desktopEntryDir,
    desktopLauncher: {
      kind: desktopLauncher.kind,
      path: desktopLauncher.path,
      markerPath: desktopLauncher.markerPath,
      targetSha256: await ownedPathSha256(desktopLauncher.path),
      markerSha256: await ownedPathSha256(desktopLauncher.markerPath)
    },
    pythonRuntime: {
      mode: pythonRuntime.mode,
      manifestPath: pythonRuntime.manifestPath,
      manifestSha256: pythonRuntime.manifestSha256,
      treeSha256: pythonRuntime.treeSha256
    },
    preservedByDefault: [path.join(installBase, "workspace")]
  };
  return { ...body, checksumSha256: sha256(stableJson(body)) };
}

async function verifyInstallationState(
  statePath,
  {
    installBase,
    releaseDir,
    currentPath,
    binDir,
    desktopEntryDir,
    desktopEntry,
    installedVersion,
    runtimeIntegrityAvailable
  }
) {
  const stateInfo = await exists(statePath);
  if (!stateInfo?.isFile() || stateInfo.isSymbolicLink()) {
    throw new Error(`Refusing an unsafe Runrail installation ownership state: ${statePath}`);
  }
  let state;
  try {
    state = JSON.parse(await readFile(statePath, "utf8"));
  } catch {
    throw new Error(`Refusing an invalid Runrail installation ownership state: ${statePath}`);
  }
  const { checksumSha256, ...body } = state;
  const expectedLaunchers = launcherDefinitions(binDir, releaseDir).map((definition) => definition.path);
  const stateLauncherPaths = Array.isArray(state.launchers)
    ? state.launchers.map((entry) => String(entry?.path || ""))
    : [];
  if (
    state.schemaVersion !== 1 ||
    state.artifactType !== "runrail-installation-ownership" ||
    state.product !== product ||
    state.managed !== true ||
    state.version !== installedVersion ||
    state.platform !== process.platform ||
    !samePath(state.installBase, installBase) ||
    !samePath(state.releaseDir, releaseDir) ||
    !samePath(state.currentPath, currentPath) ||
    !samePath(state.binDir, binDir) ||
    !samePath(state.desktopEntryDir, desktopEntryDir) ||
    JSON.stringify(stateLauncherPaths.map(pathIdentity)) !== JSON.stringify(expectedLaunchers.map(pathIdentity)) ||
    state.desktopLauncher?.kind !== desktopLauncherKind() ||
    !samePath(state.desktopLauncher?.path || "", desktopEntry.target) ||
    !samePath(state.desktopLauncher?.markerPath || "", desktopEntry.marker) ||
    checksumSha256 !== sha256(stableJson(body))
  ) {
    throw new Error(`Refusing a tampered Runrail installation ownership state: ${statePath}`);
  }

  await requireCurrentPointer(currentPath, releaseDir);
  for (const launcher of state.launchers) {
    if (!/^[a-f0-9]{64}$/.test(String(launcher.sha256 || ""))) {
      throw new Error(`Refusing an invalid Runrail launcher ownership record: ${launcher.path}`);
    }
    if ((await ownedPathSha256(launcher.path)) !== launcher.sha256) {
      throw new Error(`Refusing a tampered Runrail launcher: ${launcher.path}`);
    }
  }
  if (
    !/^[a-f0-9]{64}$/.test(String(state.desktopLauncher.targetSha256 || "")) ||
    !/^[a-f0-9]{64}$/.test(String(state.desktopLauncher.markerSha256 || ""))
  ) {
    throw new Error(`Refusing an invalid Runrail native desktop ownership record: ${desktopEntry.target}`);
  }
  const actualDesktopTargetSha256 = await ownedPathSha256(desktopEntry.target);
  const actualDesktopMarkerSha256 = await ownedPathSha256(desktopEntry.marker);
  if (actualDesktopTargetSha256 !== state.desktopLauncher.targetSha256) {
    throw new Error(
      `Refusing a tampered Runrail native desktop target: ${desktopEntry.target} ` +
      `(expected ${state.desktopLauncher.targetSha256}, received ${actualDesktopTargetSha256})`
    );
  }
  if (actualDesktopMarkerSha256 !== state.desktopLauncher.markerSha256) {
    throw new Error(
      `Refusing a tampered Runrail native desktop marker: ${desktopEntry.marker} ` +
      `(expected ${state.desktopLauncher.markerSha256}, received ${actualDesktopMarkerSha256})`
    );
  }
  if (runtimeIntegrityAvailable) {
    const pythonRuntime = await verifyRunrailPythonRuntime(releaseDir, {
      expectedDistributionVersion: installedVersion
    });
    if (
      state.pythonRuntime?.mode !== pythonRuntime.mode ||
      !samePath(state.pythonRuntime?.manifestPath || "", pythonRuntime.manifestPath) ||
      state.pythonRuntime?.manifestSha256 !== pythonRuntime.manifestSha256 ||
      state.pythonRuntime?.treeSha256 !== pythonRuntime.treeSha256
    ) {
      throw new Error(`Refusing a tampered Runrail Python runtime state: ${releaseDir}`);
    }
  } else if (state.pythonRuntime !== undefined) {
    throw new Error(`Refusing an unsupported legacy Runrail Python runtime state: ${releaseDir}`);
  }
  await requireExpectedDesktopOwnershipMarker(
    desktopEntry.marker,
    installBase,
    currentPath,
    "Runrail native desktop",
    installedVersion
  );
  return state;
}

async function requireLegacyOrEmptyInstallation({
  statePath,
  installBase,
  releaseDir,
  currentPath,
  binDir,
  desktopEntryDir,
  desktopEntry,
  existingRelease,
  installedVersion,
  runtimeIntegrityAvailable
}) {
  const stateInfo = await exists(statePath);
  if (stateInfo) {
    return verifyInstallationState(statePath, {
      installBase,
      releaseDir,
      currentPath,
      binDir,
      desktopEntryDir,
      desktopEntry,
      installedVersion,
      runtimeIntegrityAvailable
    });
  }

  const definitions = launcherDefinitions(binDir, releaseDir);
  const launcherInfos = await Promise.all(definitions.map((definition) => exists(definition.path)));
  const currentInfo = await exists(currentPath);
  if (!existingRelease) {
    if (currentInfo || launcherInfos.some(Boolean)) {
      throw new Error("Refusing unowned Runrail launcher or current-pointer paths without a verified release.");
    }
    return null;
  }

  await requireCurrentPointer(currentPath, releaseDir);
  if (!desktopEntry || !(await exists(desktopEntry.target))) {
    throw new Error("Refusing a partial legacy Runrail installation without its native desktop entry.");
  }
  await requireExpectedDesktopOwnershipMarker(
    desktopEntry.marker,
    installBase,
    currentPath,
    "legacy Runrail native desktop",
    installedVersion
  );
  for (let index = 0; index < definitions.length; index += 1) {
    const definition = definitions[index];
    const info = launcherInfos[index];
    if (!info?.isFile() || info.isSymbolicLink()) {
      throw new Error(`Refusing an unsafe legacy Runrail launcher: ${definition.path}`);
    }
    if (!(await readFile(definition.path)).equals(Buffer.from(definition.content, "utf8"))) {
      throw new Error(`Refusing an unrecognized legacy Runrail launcher: ${definition.path}`);
    }
  }
  await ownedPathSha256(desktopEntry.target);
  return null;
}

async function backupActivationState(installBase, currentPath, launcherPaths, statePath) {
  const backupRoot = await mkdtemp(path.join(installBase, ".activation-backup-"));
  const currentInfo = await exists(currentPath);
  const stateInfo = await exists(statePath);
  const launcherBackups = [];
  for (let index = 0; index < launcherPaths.length; index += 1) {
    const launcherPath = launcherPaths[index];
    const launcherInfo = await exists(launcherPath);
    if (launcherInfo) {
      const backupPath = path.join(backupRoot, `launcher-${index}`);
      await cp(launcherPath, backupPath);
      launcherBackups.push({ launcherPath, backupPath });
    }
  }
  let stateBackupPath = null;
  if (stateInfo) {
    stateBackupPath = path.join(backupRoot, "installation-state");
    await cp(statePath, stateBackupPath);
  }
  return {
    backupRoot,
    currentPath,
    currentTarget: currentInfo ? await readlink(currentPath) : null,
    launcherPaths,
    launcherBackups,
    statePath,
    stateBackupPath
  };
}

async function restoreActivationState(backup) {
  for (const launcherPath of backup.launcherPaths) await rm(launcherPath, { force: true });
  for (const launcher of backup.launcherBackups) await cp(launcher.backupPath, launcher.launcherPath);
  await rm(backup.currentPath, { force: true });
  if (backup.currentTarget) {
    await symlink(backup.currentTarget, backup.currentPath, process.platform === "win32" ? "junction" : "dir");
  }
  await rm(backup.statePath, { force: true });
  if (backup.stateBackupPath) await cp(backup.stateBackupPath, backup.statePath);
  await rm(backup.backupRoot, { recursive: true, force: true });
}

async function recoverInterruptedRelease(releaseDir, backupDir) {
  const interruptedBackup = await exists(backupDir);
  if (!interruptedBackup) return { performed: false, state: "none", restoredPriorRelease: false };
  if (!interruptedBackup.isDirectory() || interruptedBackup.isSymbolicLink()) {
    throw new Error("Refusing an unsafe interrupted Runrail update backup.");
  }
  const backupMarker = await exists(path.join(backupDir, "RUNRAIL_DISTRIBUTION.json"));
  if (!backupMarker?.isFile() || backupMarker.isSymbolicLink()) {
    throw new Error("Refusing an unrecognized interrupted Runrail update backup.");
  }
  await verifyCompatiblePriorRunrailDistribution(backupDir);

  const releaseInfo = await exists(releaseDir);
  if (!releaseInfo) {
    await rename(backupDir, releaseDir);
    return { performed: true, state: "backup-only", restoredPriorRelease: true };
  }
  if (!releaseInfo.isDirectory() || releaseInfo.isSymbolicLink()) {
    throw new Error("Refusing an unsafe new release beside an interrupted Runrail update backup.");
  }
  await verifyCompatiblePriorRunrailDistribution(releaseDir);
  await rm(releaseDir, { recursive: true });
  await rename(backupDir, releaseDir);
  return { performed: true, state: "backup-and-new-release", restoredPriorRelease: true };
}

async function isBinDirOnPath(binDir) {
  const pathValue = String(process.env.PATH || process.env.Path || "");
  const entries = pathValue
    .split(path.delimiter)
    .map((entry) => entry.trim().replace(/^"(.*)"$/, "$1"))
    .filter(Boolean);
  for (const entry of entries) {
    if (samePath(entry, binDir)) return true;
    try {
      if (samePath(await canonicalTarget(entry), binDir)) return true;
    } catch {
      // Ignore inaccessible PATH entries; they cannot identify this launcher.
    }
  }
  return false;
}

function fullPathCommand(commandPath, args) {
  if (process.platform === "win32") {
    return `& "${String(commandPath).replaceAll('"', '""')}"${args.length ? ` ${args.join(" ")}` : ""}`;
  }
  return `${shellQuote(commandPath)}${args.length ? ` ${args.join(" ")}` : ""}`;
}

async function updateCurrentPointer(installBase, releaseDir) {
  const currentPath = path.join(installBase, "current");
  const currentInfo = await exists(currentPath);
  if (currentInfo) {
    if (!currentInfo.isSymbolicLink()) {
      throw new Error("Refusing to replace an unrecognized Runrail current pointer.");
    }
    await rm(currentPath, { force: true });
  }
  await symlink(releaseDir, currentPath, process.platform === "win32" ? "junction" : "dir");
  return currentPath;
}

const installBase = await safeInstallRoot(process.env.RUNRAIL_INSTALL_BASE || defaultInstallBase());
const binDir = await safeInstallRoot(process.env.RUNRAIL_BIN_DIR || defaultBinDir(installBase));
const desktopEntryDir = await safeInstallRoot(process.env.RUNRAIL_DESKTOP_ENTRY_DIR || defaultDesktopEntryDir());
const releasesRoot = path.join(installBase, "releases");
const releaseDir = path.join(releasesRoot, "v1");
const backupDir = path.join(releasesRoot, ".v1-backup");
const currentPath = path.join(installBase, "current");
const statePath = path.join(installBase, installationStateName);

const desktopEntry = desktopEntryPaths(desktopEntryDir);
await verifyRunrailDistribution(sourceRoot);
await mkdir(releasesRoot, { recursive: true });
const recovery = await recoverInterruptedRelease(releaseDir, backupDir);
let existingRelease = await exists(releaseDir);
let installedVersion = null;
let installedRuntimeIntegrityAvailable = false;
if (existingRelease) {
  if (!existingRelease.isDirectory() || existingRelease.isSymbolicLink()) {
    throw new Error("Refusing to replace an unsafe Runrail release path.");
  }
  const marker = await exists(path.join(releaseDir, "RUNRAIL_DISTRIBUTION.json"));
  if (!marker?.isFile() || marker.isSymbolicLink()) {
    throw new Error("Refusing to replace an unrecognized Runrail release directory.");
  }
  const existingDistribution = await verifyCompatiblePriorRunrailDistribution(releaseDir);
  installedVersion = existingDistribution.version;
  installedRuntimeIntegrityAvailable = existingDistribution.runtimeIntegrityAvailable;
}
await requireOwnedEntry(desktopEntry.target, desktopEntry.marker);
await requireLegacyOrEmptyInstallation({
  statePath,
  installBase,
  releaseDir,
  currentPath,
  binDir,
  desktopEntryDir,
  desktopEntry,
  existingRelease,
  installedVersion,
  runtimeIntegrityAvailable: installedRuntimeIntegrityAvailable
});

const workspaceRoot = path.join(installBase, "workspace");
await mkdir(workspaceRoot, { recursive: true, mode: 0o700 });
if (process.platform !== "win32") await chmod(workspaceRoot, 0o700);
const stageDir = await mkdtemp(path.join(releasesRoot, ".v1-stage-"));
let backupCreated = false;
let stageMoved = false;
let installSucceeded = false;
let desktopEntryBackup = null;
let activationBackup = null;
let cleanupWarnings = [];
try {
  await cp(sourceRoot, stageDir, {
    recursive: true,
    filter: (source) => !source.split(path.sep).includes("python-env")
  });
  await verifyRunrailDistribution(stageDir);
  const python = await resolveBootstrapPython();
  await execFileAsync(
    python.command,
    [...python.prefixArgs, "-m", "venv", "--without-pip", path.join(stageDir, "python-env")],
    {
      timeout: 120_000,
      maxBuffer: 2 * 1024 * 1024,
      windowsHide: true
    }
  );

  if (existingRelease) {
    await rename(releaseDir, backupDir);
    backupCreated = true;
  }
  await rename(stageDir, releaseDir);
  stageMoved = true;
  const pythonRuntime = await createRunrailPythonRuntimeManifest(releaseDir, {
    distributionVersion,
    pythonVersion: python.version
  });

  const expectedLauncherPaths = launcherDefinitions(binDir, releaseDir).map((definition) => definition.path);
  activationBackup = await backupActivationState(installBase, currentPath, expectedLauncherPaths, statePath);
  desktopEntryBackup = await backupDesktopEntry(desktopEntry, installBase);
  await updateCurrentPointer(installBase, releaseDir);
  const launchers = await writeLaunchers(binDir, releaseDir);
  const desktopLauncher = await writeDesktopEntry(
    desktopEntryDir,
    currentPath,
    path.join(installBase, "workspace"),
    installBase,
    binDir
  );
  const installationState = await buildInstallationState({
    installBase,
    releaseDir,
    currentPath,
    binDir,
    launchers,
    desktopEntryDir,
    desktopLauncher,
    pythonRuntime
  });
  await writeFile(statePath, stableJson(installationState), "utf8");
  await verifyInstallationState(statePath, {
    installBase,
    releaseDir,
    currentPath,
    binDir,
    desktopEntryDir,
    desktopEntry,
    installedVersion: distributionVersion,
    runtimeIntegrityAvailable: true
  });
  const doctorOperatorRoot = [
    process.env.RUNRAIL_OPERATOR_ROOT,
    process.env.RUNRAIL_HOME
  ].map((value) => String(value || "").trim()).find(Boolean) || path.join(installBase, "workspace");
  const { stdout: doctorOutput } = await execFileAsync(
    process.execPath,
    [path.join(releaseDir, "bin", "runrail.mjs"), "doctor", "--json"],
    {
      env: { ...process.env, RUNRAIL_OPERATOR_ROOT: doctorOperatorRoot },
      timeout: 60_000,
      maxBuffer: 2 * 1024 * 1024,
      windowsHide: true
    }
  );
  const doctor = JSON.parse(doctorOutput);
  if (doctor.ok !== true) throw new Error("Runrail doctor did not pass after installation lifecycle verification.");

  let retiredReleaseBackup = null;
  if (backupCreated) {
    retiredReleaseBackup = path.join(releasesRoot, `.v1-retired-${randomUUID()}`);
    await rename(backupDir, retiredReleaseBackup);
    backupCreated = false;
  }
  installSucceeded = true;
  const committedCleanupTargets = [
    { target: retiredReleaseBackup, label: "retired-prior-release" },
    { target: desktopEntryBackup.backupRoot, label: "desktop-entry-activation-backup" },
    { target: activationBackup.backupRoot, label: "launcher-activation-backup" }
  ];
  desktopEntryBackup = null;
  activationBackup = null;
  for (const cleanupTarget of committedCleanupTargets) {
    await removeCommittedCleanupTarget(cleanupTarget.target, cleanupTarget.label, cleanupWarnings);
  }

  const binDirOnPath = await isBinDirOnPath(binDir);
  const commandLauncher = process.platform === "win32"
    ? path.join(binDir, "runrail.cmd")
    : path.join(binDir, "runrail");
  process.stdout.write(`${JSON.stringify({
    ok: true,
    product,
    platform: `${process.platform}-${process.arch}`,
    installBase,
    releaseDir,
    currentPath,
    installationStatePath: statePath,
    binDir,
    launchers,
    desktopEntryDir,
    desktopLauncher,
    python: python.version,
    upgrade: {
      fromVersion: installedVersion,
      toVersion: distributionVersion,
      performed: Boolean(installedVersion && installedVersion !== distributionVersion),
      releaseLine: "v1"
    },
    doctor,
    recovery,
    maintenance: {
      cleanupWarnings
    },
    path: {
      binDirOnPath,
      pathModified: false,
      shellProfilesModified: false
    },
    nextCommands: {
      doctor: binDirOnPath
        ? "runrail doctor --json"
        : fullPathCommand(commandLauncher, ["doctor", "--json"]),
      licenseRequest: binDirOnPath
        ? "runrail license request --json"
        : fullPathCommand(commandLauncher, ["license", "request", "--json"]),
      licenseEnroll: binDirOnPath
        ? "runrail license enroll --ticket /absolute/path/to/ticket.json --json"
        : fullPathCommand(commandLauncher, [
          "license",
          "enroll",
          "--ticket",
          "/absolute/path/to/ticket.json",
          "--json"
        ]),
      licenseStatus: binDirOnPath
        ? "runrail license --json"
        : fullPathCommand(commandLauncher, ["license", "--json"]),
      sample: binDirOnPath
        ? "runrail sample --json"
        : fullPathCommand(commandLauncher, ["sample", "--json"]),
      desktop: binDirOnPath
        ? "runrail desktop"
        : fullPathCommand(commandLauncher, ["desktop"]),
      desktopCurrentRepository: binDirOnPath
        ? "runrail desktop --repo ."
        : fullPathCommand(commandLauncher, ["desktop", "--repo", "."]),
      review: binDirOnPath
        ? "runrail review --repo /path/to/clean-repo --base main --candidate ai/change --verifier safe-static --json"
        : fullPathCommand(commandLauncher, [
          "review",
          "--repo",
          "/path/to/clean-repo",
          "--base",
          "main",
          "--candidate",
          "ai/change",
          "--verifier",
          "safe-static",
          "--json"
        ])
    }
  }, null, 2)}\n`);
} finally {
  if (!stageMoved) await rm(stageDir, { recursive: true, force: true });
  if (!installSucceeded) {
    if (stageMoved) await rm(releaseDir, { recursive: true, force: true });
    if (backupCreated) {
      await rename(backupDir, releaseDir);
      backupCreated = false;
    }
    if (activationBackup) {
      await restoreActivationState(activationBackup);
      activationBackup = null;
    }
    if (desktopEntryBackup) {
      await restoreDesktopEntry(desktopEntryBackup);
      desktopEntryBackup = null;
    }
  }
}
