// src/lib/deprecationMigrate.ts
import {
  existsSync as existsSync3,
  readFileSync as readFileSync2,
  writeFileSync
} from "fs";
import { createRequire } from "module";
import PATH2 from "path";
import { createInterface } from "readline";
import chalk2 from "chalk";
import semver from "semver";

// src/lib/packageManagerRuntime.ts
import { spawnSync } from "child_process";
import fs from "fs";
import chalk from "chalk";
var DISPLAY_NAMES = {
  bun: "Bun",
  npm: "npm",
  pnpm: "pnpm",
  yarn: "Yarn"
};
var MAC_INSTALL_COMMANDS = {
  bun: "brew install oven-sh/bun/bun",
  npm: "brew install node",
  pnpm: "brew install pnpm",
  yarn: "brew install yarn"
};
function currentPlatform() {
  if (process.platform === "darwin" || process.platform === "linux" || process.platform === "win32") {
    return process.platform;
  }
  return "unknown";
}
function askYesNo(question) {
  if (!process.stdin.isTTY || !process.stdout.isTTY) {
    return false;
  }
  process.stdout.write(question);
  const buffer = Buffer.alloc(1024);
  const bytesRead = fs.readSync(process.stdin.fd, buffer, 0, buffer.length, null);
  const answer = buffer.toString("utf8", 0, bytesRead).trim().toLowerCase();
  return answer === "y" || answer === "yes";
}
function isCommandInstalled(command) {
  const result = spawnSync(command, ["--version"], {
    encoding: "utf8",
    shell: false,
    stdio: "ignore"
  });
  return !result.error && result.status === 0;
}
function isPackageManagerInstalled(pm) {
  return isCommandInstalled(pm);
}
function getPackageManagerInstallPlan(pm, platform = currentPlatform()) {
  const displayName = DISPLAY_NAMES[pm];
  if (platform === "darwin") {
    const command = MAC_INSTALL_COMMANDS[pm];
    return {
      command,
      manualInstructions: [
        `Install ${displayName} with: ${command}`
      ],
      packageManager: pm,
      platform,
      supported: true
    };
  }
  if (platform === "linux") {
    return {
      manualInstructions: [
        `Automatic installation for ${displayName} is not implemented on Linux yet.`,
        `Install ${displayName} manually and re-run the command.`
      ],
      packageManager: pm,
      platform,
      supported: false
    };
  }
  if (platform === "win32") {
    return {
      manualInstructions: [
        `Automatic installation for ${displayName} is not implemented on Windows yet.`,
        `Install ${displayName} manually and re-run the command.`
      ],
      packageManager: pm,
      platform,
      supported: false
    };
  }
  return {
    manualInstructions: [
      `Automatic installation for ${displayName} is not implemented on ${platform} yet.`,
      `Install ${displayName} manually and re-run the command.`
    ],
    packageManager: pm,
    platform,
    supported: false
  };
}
function printManualInstructions(plan, context) {
  console.error(chalk.yellow(`${DISPLAY_NAMES[plan.packageManager]} is required for "${context.operation}".`));
  for (const line of plan.manualInstructions) {
    console.error(chalk.gray(`  ${line}`));
  }
}
function installWithHomebrew(pm, cwd) {
  const command = MAC_INSTALL_COMMANDS[pm];
  const result = spawnSync("brew", command.replace("brew ", "").split(" "), {
    cwd,
    encoding: "utf8",
    shell: false,
    stdio: "inherit"
  });
  return result.status === 0;
}
function ensurePackageManagerInstalled(pm, context) {
  if (isPackageManagerInstalled(pm)) return true;
  const plan = getPackageManagerInstallPlan(pm, context.platform ?? currentPlatform());
  const displayName = DISPLAY_NAMES[pm];
  console.error(chalk.yellow(`${context.operation} requires ${displayName}, but it is not installed.`));
  if (!plan.supported) {
    printManualInstructions(plan, context);
    return false;
  }
  if (!isCommandInstalled("brew")) {
    console.error(chalk.yellow("Homebrew is not installed, so automatic installation is unavailable."));
    console.error(chalk.gray("  Install Homebrew from https://brew.sh and then run:"));
    console.error(chalk.gray(`  ${plan.command}`));
    return false;
  }
  const confirmed = askYesNo(chalk.cyan(`Install ${displayName} with Homebrew now? [y/N] `));
  if (!confirmed) {
    console.error(chalk.gray(`Skipping install. Run "${plan.command}" manually and then retry.`));
    return false;
  }
  console.error(chalk.cyan(`Installing ${displayName} via Homebrew...
`));
  if (!installWithHomebrew(pm, context.cwd)) {
    console.error(chalk.red(`Homebrew failed to install ${displayName}.`));
    console.error(chalk.gray(`Run "${plan.command}" manually and then retry.`));
    return false;
  }
  if (!isPackageManagerInstalled(pm)) {
    console.error(chalk.red(`${displayName} still does not appear to be installed after Homebrew completed.`));
    console.error(chalk.gray(`Run "${plan.command}" manually and then retry.`));
    return false;
  }
  console.error(chalk.green(`${displayName} installed successfully.`));
  return true;
}
function failureResult() {
  return {
    output: ["", ""],
    pid: 0,
    signal: null,
    status: 1,
    stderr: "",
    stdout: ""
  };
}
function spawnPackageManagerSync(pm, args, options) {
  if (!ensurePackageManagerInstalled(pm, options.context)) {
    return failureResult();
  }
  return spawnSync(pm, args, { encoding: "utf8", ...options });
}

// src/pm/workspaces.ts
import { existsSync, readFileSync } from "fs";
import PATH from "path";
import { globSync } from "glob";
function readJsonFile(path) {
  if (!existsSync(path)) return void 0;
  try {
    return JSON.parse(readFileSync(path, "utf8"));
  } catch {
    return void 0;
  }
}
function readRootPackageJson(cwd = process.cwd()) {
  return readJsonFile(PATH.resolve(cwd, "package.json"));
}
function detectPackageManagerFromPackageJson(cwd = process.cwd()) {
  const packageManager = readRootPackageJson(cwd)?.packageManager;
  if (!packageManager) return void 0;
  return packageManager.split("@")[0];
}

// src/pm/detectPackageManager.ts
import { existsSync as existsSync2 } from "fs";
var knownPackageManagers = /* @__PURE__ */ new Set(["bun", "npm", "pnpm", "yarn"]);
function detectPackageManager() {
  const packageManager = detectPackageManagerFromPackageJson();
  if (packageManager && knownPackageManagers.has(packageManager)) {
    return packageManager;
  }
  if (existsSync2("pnpm-lock.yaml") || existsSync2("pnpm-workspace.yaml")) return "pnpm";
  if (existsSync2("bun.lock") || existsSync2("bun.lockb")) return "bun";
  if (existsSync2("yarn.lock") || existsSync2(".yarnrc.yml")) return "yarn";
  if (existsSync2("package-lock.json") || existsSync2("npm-shrinkwrap.json")) return "npm";
  return "yarn";
}

// src/lib/npmLatestVersion.ts
var REGISTRY_BASE = "https://registry.npmjs.org";
var cache = /* @__PURE__ */ new Map();
async function fetchUncached(packageName) {
  try {
    const url = `${REGISTRY_BASE}/${encodeURIComponent(packageName)}/latest`;
    const res = await fetch(url, { headers: { Accept: "application/vnd.npm.install-v1+json" } });
    if (!res.ok) return void 0;
    const data = await res.json();
    return data.version;
  } catch {
    return void 0;
  }
}
function fetchLatestPackageVersion(packageName) {
  const existing = cache.get(packageName);
  if (existing) return existing;
  const pending = fetchUncached(packageName);
  cache.set(packageName, pending);
  return pending;
}

// src/lib/deprecationMigrate.ts
var DEPRECATED_PACKAGES = [
  "@xylabs/ts-scripts-common",
  "@xylabs/ts-scripts-yarn3",
  "@xylabs/ts-scripts-pnpm",
  "@xylabs/ts-scripts-react-yarn3"
];
function findProjectRoot() {
  return process.env.INIT_CWD ?? process.cwd();
}
function askYesNo2(question) {
  const rl = createInterface({ input: process.stdin, output: process.stderr });
  return new Promise((resolve) => {
    rl.question(question, (answer) => {
      rl.close();
      resolve(answer.trim().toLowerCase().startsWith("y"));
    });
  });
}
function replaceAllOldPackagesInFile(filePath) {
  if (!existsSync3(filePath)) return false;
  let content = readFileSync2(filePath, "utf8");
  let changed = false;
  for (const oldPkg of DEPRECATED_PACKAGES) {
    if (content.includes(oldPkg)) {
      content = content.replaceAll(oldPkg, "@xylabs/toolchain");
      changed = true;
    }
  }
  if (changed) {
    writeFileSync(filePath, content, "utf8");
  }
  return changed;
}
function applyVersionStyle(previousVersion, latestVersion) {
  if (!previousVersion) return `^${latestVersion}`;
  if (previousVersion.startsWith("~")) return `~${latestVersion}`;
  if (previousVersion.startsWith("^")) return `^${latestVersion}`;
  if (semver.valid(previousVersion)) return latestVersion;
  return `^${latestVersion}`;
}
function findPreferredVersion(pkg, field) {
  return pkg[field]?.["@xylabs/toolchain"] ?? DEPRECATED_PACKAGES.map((name) => pkg[field]?.[name]).find(Boolean);
}
function migratePackageJson(pkgPath, label, latestToolchainVersion) {
  if (!existsSync3(pkgPath)) return false;
  const pkg = JSON.parse(readFileSync2(pkgPath, "utf8"));
  let changed = false;
  for (const field of ["dependencies", "devDependencies", "peerDependencies"]) {
    const previousVersion = findPreferredVersion(pkg, field);
    let foundDeprecatedPackage = false;
    for (const oldPkg of DEPRECATED_PACKAGES) {
      if (pkg[field]?.[oldPkg]) {
        delete pkg[field][oldPkg];
        changed = true;
        foundDeprecatedPackage = true;
      }
    }
    if (foundDeprecatedPackage || pkg[field]?.["@xylabs/toolchain"]) {
      pkg[field] ??= {};
      pkg[field]["@xylabs/toolchain"] = applyVersionStyle(previousVersion, latestToolchainVersion);
      changed = true;
    }
  }
  if (changed) {
    writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}
`, "utf8");
    console.warn(chalk2.green(`  \u2713 Updated ${label}`));
  }
  return changed;
}
async function migrateWorkspaces(root, latestToolchainVersion) {
  const { globSync: globSync2 } = await import("glob");
  const packageJsonFiles = globSync2("**/package.json", {
    cwd: root,
    ignore: ["node_modules/**", "**/node_modules/**", "dist/**", "**/dist/**"]
  });
  for (const relPath of packageJsonFiles) {
    if (relPath === "package.json") continue;
    const dir = PATH2.dirname(relPath);
    migratePackageJson(PATH2.join(root, relPath), relPath, latestToolchainVersion);
    const xyConfigPath = PATH2.join(root, dir, "xy.config.ts");
    if (replaceAllOldPackagesInFile(xyConfigPath)) {
      console.warn(chalk2.green(`  \u2713 Updated ${dir}/xy.config.ts`));
    }
  }
}
function printManualInstructions2() {
  console.warn(chalk2.gray("  Skipped. To migrate manually:\n"));
  console.warn(chalk2.gray("    1. Replace all @xylabs/ts-scripts-* deps with @xylabs/toolchain in package.json"));
  console.warn(chalk2.gray("    2. Update imports in xy.config.ts files"));
  console.warn(chalk2.gray("    3. Run your package manager install\n"));
}
function bundledToolchainVersion() {
  try {
    const require2 = createRequire(import.meta.url);
    const pkgPath = require2.resolve("@xylabs/toolchain/package.json");
    const pkg = JSON.parse(readFileSync2(pkgPath, "utf8"));
    return pkg.version;
  } catch {
    return void 0;
  }
}
async function resolveLatestToolchainVersion(pkg) {
  const latest = await fetchLatestPackageVersion("@xylabs/toolchain");
  if (latest) return latest;
  const existing = ["dependencies", "devDependencies", "peerDependencies"].map((field) => findPreferredVersion(pkg, field)).find(Boolean);
  if (existing) {
    console.warn(chalk2.yellow("  Unable to reach npm for @xylabs/toolchain latest; falling back to existing toolchain version instead of npm latest."));
    return existing.replace(/^[~^]/, "");
  }
  const bundled = bundledToolchainVersion();
  if (bundled) {
    console.warn(chalk2.yellow(`  Unable to reach npm for @xylabs/toolchain latest; falling back to bundled toolchain version ${bundled}.`));
    return bundled;
  }
  console.warn(chalk2.yellow("  Unable to reach npm for @xylabs/toolchain latest; falling back to default toolchain version 7.11.12."));
  return "7.11.12";
}
async function deprecationMigrate(oldPackage) {
  const root = findProjectRoot();
  const pkgPath = PATH2.join(root, "package.json");
  if (!existsSync3(pkgPath)) return;
  const pkg = JSON.parse(readFileSync2(pkgPath, "utf8"));
  const hasOldDep = DEPRECATED_PACKAGES.some((dep) => pkg.dependencies?.[dep] || pkg.devDependencies?.[dep]);
  if (!hasOldDep) return;
  console.warn(chalk2.yellow(`
\u26A0  ${oldPackage} is deprecated. Use @xylabs/toolchain instead.
`));
  const shouldMigrate = await askYesNo2(chalk2.cyan("  Auto-migrate to @xylabs/toolchain? [y/N] "));
  if (!shouldMigrate) {
    printManualInstructions2();
    return;
  }
  const latestToolchainVersion = await resolveLatestToolchainVersion(pkg);
  migratePackageJson(pkgPath, "package.json", latestToolchainVersion);
  if (replaceAllOldPackagesInFile(PATH2.join(root, "xy.config.ts"))) {
    console.warn(chalk2.green("  \u2713 Updated xy.config.ts"));
  }
  await migrateWorkspaces(root, latestToolchainVersion);
  const pm = detectPackageManager();
  console.warn(chalk2.cyan(`
  Running ${pm} install...
`));
  const result = spawnPackageManagerSync(pm, ["install"], {
    context: { cwd: root, operation: `Run ${pm} install after toolchain migration` },
    cwd: root,
    encoding: "utf8",
    stdio: "inherit"
  });
  if (result.status === 0) {
    console.warn(chalk2.green("  \u2713 Migration complete. Re-run your command.\n"));
  } else {
    console.warn(chalk2.red(`  Install failed (exit ${result.status}). Run "${pm} install" manually.
`));
  }
  process.exit(result.status ?? 1);
}
export {
  deprecationMigrate
};
//# sourceMappingURL=deprecationMigrate.mjs.map