// src/actions/repo-init.ts
import {
  existsSync,
  mkdirSync,
  readdirSync as readdirSync2,
  readFileSync as readFileSync3,
  writeFileSync
} from "node:fs";
import PATH2 from "node:path";
import { createInterface } from "node:readline";
import chalk2 from "chalk";

// src/lib/crossSpawn.ts
import crossSpawn from "cross-spawn";
function spawnSync(command, args, options) {
  return crossSpawn.sync(command, args, options);
}

// src/lib/packageManagerRuntime.ts
import fs from "node: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",
    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",
    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/lib/toolchainVersion.ts
import { readFileSync } from "node:fs";
import { createRequire } from "node:module";
var require2 = createRequire(import.meta.url);
function bundledToolchainVersion() {
  const pkgPath = require2.resolve("@xylabs/toolchain/package.json");
  const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
  if (!pkg.version) throw new Error("Could not read @xylabs/toolchain version");
  return pkg.version;
}
function bundledToolchainRange() {
  return `^${bundledToolchainVersion()}`;
}

// src/lib/fillTemplate.ts
function fillTemplate(template, data) {
  return template.replaceAll(/\{\{(.*?)\}\}/g, (_, key) => data[key.trim()] ?? "");
}

// src/lib/repoTemplates.ts
import { readdirSync, readFileSync as readFileSync2 } from "node:fs";
import { createRequire as createRequire2 } from "node:module";
import PATH from "node:path";
var require3 = createRequire2(import.meta.url);
var packageRoot = PATH.dirname(require3.resolve("@xylabs/toolchain/package.json"));
var repoTemplatesDir = PATH.resolve(packageRoot, "templates", "repo");
function collectFiles(dir, prefix) {
  const results = [];
  for (const entry of readdirSync(dir, { withFileTypes: true })) {
    const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
    if (entry.isDirectory()) {
      results.push(...collectFiles(PATH.resolve(dir, entry.name), rel));
    } else {
      results.push({
        content: readFileSync2(PATH.resolve(dir, entry.name), "utf8"),
        relativePath: rel
      });
    }
  }
  return results;
}
function loadRepoTemplateFiles(template, section) {
  const dir = PATH.resolve(repoTemplatesDir, template, section);
  return collectFiles(dir, "");
}

// src/actions/repo-init.ts
function askQuestion(question) {
  const rl = createInterface({ input: process.stdin, output: process.stdout });
  return new Promise((resolve) => {
    rl.question(question, (answer) => {
      rl.close();
      resolve(answer.trim());
    });
  });
}
function mapOutputPath(relativePath, variables) {
  let result = relativePath;
  if (result.endsWith(".tmpl")) {
    result = result.slice(0, -5);
  }
  if (result === "gitignore") {
    result = ".gitignore";
  }
  if (result.startsWith("github/")) {
    result = `.${result}`;
  }
  result = result.replaceAll("__packageName__", variables.packageName);
  return result;
}
function isPmSpecificFile(relativePath, pm) {
  if (relativePath === "pnpm-workspace.yaml" && pm !== "pnpm") return true;
  if (relativePath.includes("build-pnpm") && pm !== "pnpm") return true;
  if (relativePath.includes("build-npm") && pm !== "npm") return true;
  if (relativePath.includes("build-bun") && pm !== "bun") return true;
  if (relativePath.includes("build-yarn") && pm !== "yarn") return true;
  return false;
}
function mapBuildWorkflowName(outputPath) {
  return outputPath.replace(/build-(bun|npm|pnpm|yarn)\.yml/, "build.yml");
}
function buildVariables(params) {
  const {
    description,
    githubOrg,
    packageName,
    pm,
    projectName,
    scope
  } = params;
  const identifierName = packageName.replaceAll(/-([a-z])/g, (_, c) => c.toUpperCase());
  const packageManager = pm === "pnpm" ? "pnpm@10.33.0+sha512.10568bb4a6afb58c9eb3630da90cc9516417abebd3fabbe6739f0ae795728da1491e9db5a544c76ad8eb7570f5c4bb3d6c637b2cb41bfdcdb47fa823c8649319" : pm === "yarn" ? "yarn@4.13.0" : pm === "npm" ? "npm@10.9.4" : "bun@1.3.3";
  const xyCommand = pm === "npm" ? "npm exec -- xy" : pm === "bun" ? "bun run xy" : `${pm} xy`;
  return {
    description,
    githubOrg,
    identifierName,
    npmScope: scope,
    packageName,
    packageManager,
    pmName: pm,
    projectName,
    toolchainRange: bundledToolchainRange(),
    toolchainVersion: bundledToolchainVersion(),
    xyCommand
  };
}
function ensureEmptyDir(projectDir, name) {
  if (existsSync(projectDir)) {
    const entries = readdirSync2(projectDir);
    if (entries.length > 0) {
      console.error(chalk2.red(`Directory '${name}' already exists and is not empty`));
      return false;
    }
  }
  mkdirSync(projectDir, { recursive: true });
  return true;
}
function scaffoldFiles(templateName, layer, outputDir, pm, variables, verbose) {
  const files = loadRepoTemplateFiles(templateName, layer);
  let count = 0;
  for (const file of files) {
    if (isPmSpecificFile(file.relativePath, pm)) continue;
    const content = fillTemplate(file.content, variables);
    let outputPath = mapOutputPath(file.relativePath, variables);
    if (!outputPath) continue;
    if (layer === "root") outputPath = mapBuildWorkflowName(outputPath);
    const fullPath = PATH2.resolve(outputDir, outputPath);
    mkdirSync(PATH2.dirname(fullPath), { recursive: true });
    writeFileSync(fullPath, content);
    count++;
    if (verbose) console.log(chalk2.gray(`  ${layer === "root" ? outputPath : `packages/${variables.packageName}/${outputPath}`}`));
  }
  return count;
}
function initGitRepo(projectDir, verbose) {
  if (verbose) console.log(chalk2.gray("Initializing git repository..."));
  const result = spawnSync("git", ["init", "-b", "main"], {
    cwd: projectDir,
    stdio: verbose ? "inherit" : "pipe"
  });
  if (result.status === 0) {
    console.log(chalk2.green("Initialized git repository"));
  } else {
    console.warn(chalk2.yellow("git init failed, skipping"));
  }
}
function installDependencies(projectDir, pm) {
  console.log(chalk2.gray(`Running ${pm} install...`));
  const result = spawnPackageManagerSync(pm, ["install"], {
    context: { cwd: projectDir, operation: `Install ${pm} dependencies for repo init` },
    cwd: projectDir,
    encoding: "utf8",
    stdio: "inherit"
  });
  if (result.status !== 0) {
    console.warn(chalk2.yellow(`${pm} install failed`));
    return false;
  }
  console.log(chalk2.green("Dependencies installed"));
  return true;
}
function normalizeRootPackageJson(projectDir, pm) {
  const pkgPath = PATH2.resolve(projectDir, "package.json");
  const pkg = JSON.parse(readFileSync3(pkgPath, "utf8"));
  if (pm === "pnpm") {
    delete pkg.workspaces;
  } else {
    pkg.workspaces ??= ["packages/*"];
  }
  writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}
`, "utf8");
}
function renderXyCommand(pm, args) {
  const suffix = args.join(" ");
  switch (pm) {
    case "bun": {
      return `bun run xy ${suffix}`.trim();
    }
    case "npm": {
      return `npm exec -- xy ${suffix}`.trim();
    }
    default: {
      return `${pm} xy ${suffix}`.trim();
    }
  }
}
async function repoInit(params) {
  const {
    description,
    pm,
    scope,
    skipGit,
    skipInstall,
    template,
    verbose
  } = params;
  let name = params.name;
  if (!name) {
    name = await askQuestion(chalk2.cyan("Project name: "));
    if (!name) {
      console.error(chalk2.red("Project name is required"));
      return 1;
    }
  }
  const projectName = PATH2.basename(name);
  const packageName = params.packageName ?? projectName;
  const githubOrg = params.githubOrg ?? scope.replace(/^@/, "");
  const variables = buildVariables({
    description,
    githubOrg,
    packageName,
    pm,
    projectName,
    scope
  });
  if (verbose) {
    console.log(chalk2.gray("Template variables:"));
    for (const [key, value] of Object.entries(variables)) {
      console.log(chalk2.gray(`  ${key}: ${value}`));
    }
  }
  const projectDir = PATH2.resolve(process.cwd(), name);
  if (!ensureEmptyDir(projectDir, name)) return 1;
  const rootCount = scaffoldFiles(template, "root", projectDir, pm, variables, verbose);
  const pkgDir = PATH2.resolve(projectDir, "packages", packageName);
  const pkgCount = scaffoldFiles(template, "package", pkgDir, pm, variables, verbose);
  normalizeRootPackageJson(projectDir, pm);
  console.log(chalk2.green(`Scaffolded ${rootCount + pkgCount} files into ${name}/`));
  if (!skipGit) initGitRepo(projectDir, verbose);
  if (!skipInstall && !installDependencies(projectDir, pm)) return 1;
  console.log("");
  console.log(chalk2.cyan(`Project ${name} created successfully!`));
  console.log("");
  console.log(chalk2.gray("Next steps:"));
  console.log(chalk2.gray(`  cd ${name}`));
  if (skipInstall) console.log(chalk2.gray(`  ${pm} install`));
  console.log(chalk2.gray(`  ${renderXyCommand(pm, ["build"])}`));
  return 0;
}
export {
  repoInit
};
//# sourceMappingURL=repo-init.mjs.map
