#!/usr/bin/env node
import { Command } from "commander";
import { existsSync, readFileSync, writeFileSync, readdirSync, statSync, rmSync, mkdirSync, copyFileSync } from "node:fs";
import { dirname, resolve, join } from "node:path";
import { homedir } from "node:os";
import { fileURLToPath } from "node:url";
const log = (message) => {
  process.stdout.write(`${message}
`);
};
const fail = (message, code = 1) => {
  process.stderr.write(`fondue: ${message}
`);
  process.exit(code);
};
const TOOL_DIR = dirname(fileURLToPath(import.meta.url));
const SKILL_SOURCE_DIR = resolve(TOOL_DIR, "adapters", "claude-skill", "skill");
const SKILL_NAME = "fondue";
const CONSUMER_PACKAGE = "@frontify/fondue";
const FONDUE_VERSION = "13.6.2";
const scopeOf = (options) => options.user ? "user" : "project";
const projectRoot = () => {
  let dir = process.cwd();
  while (true) {
    if (existsSync(join(dir, "package.json")) || existsSync(join(dir, ".git"))) {
      return dir;
    }
    const parent = dirname(dir);
    if (parent === dir) {
      return process.cwd();
    }
    dir = parent;
  }
};
const skillsRoot = (scope) => scope === "user" ? join(homedir(), ".claude", "skills") : join(projectRoot(), ".claude", "skills");
const targetDirFor = (scope) => join(skillsRoot(scope), SKILL_NAME);
const stampPathFor = (scope) => join(skillsRoot(scope), `.${SKILL_NAME}-installed.json`);
const readStamp = (stampPath) => {
  if (!existsSync(stampPath)) {
    return { status: "missing" };
  }
  try {
    const stamp = JSON.parse(readFileSync(stampPath, "utf8"));
    return { status: "ok", stamp };
  } catch (error) {
    return { status: "corrupted", error: error instanceof Error ? error.message : String(error) };
  }
};
const writeStamp = (stampPath, scope) => {
  const stamp = {
    package: CONSUMER_PACKAGE,
    version: FONDUE_VERSION,
    installedAt: (/* @__PURE__ */ new Date()).toISOString(),
    scope
  };
  writeFileSync(stampPath, `${JSON.stringify(stamp, null, 2)}
`);
};
const install = (options) => {
  const scope = scopeOf(options);
  const target = targetDirFor(scope);
  const stampPath = stampPathFor(scope);
  if (!existsSync(SKILL_SOURCE_DIR)) {
    fail(`Bundled skill directory missing at ${SKILL_SOURCE_DIR}. Reinstall ${CONSUMER_PACKAGE}.`);
  }
  const files = readdirSync(SKILL_SOURCE_DIR).filter((name) => statSync(join(SKILL_SOURCE_DIR, name)).isFile());
  if (!files.includes("SKILL.md")) {
    fail(`Bundled skill is missing SKILL.md. Reinstall ${CONSUMER_PACKAGE}.`);
  }
  let previousVersion = null;
  if (existsSync(target)) {
    const read = readStamp(stampPath);
    if (read.status === "ok") {
      previousVersion = read.stamp.version;
    } else if (read.status === "corrupted" && !options.force) {
      fail(
        `Stamp file at ${stampPath} is unreadable (${read.error}). Inspect it, or pass --force to overwrite both the stamp and the skill.`
      );
    } else if (read.status === "missing" && !options.force) {
      fail(
        `${target} exists and was not installed by this CLI. Remove it manually, or pass --force to overwrite.`
      );
    }
    rmSync(target, { recursive: true, force: true });
  }
  mkdirSync(target, { recursive: true });
  for (const name of files) {
    copyFileSync(join(SKILL_SOURCE_DIR, name), join(target, name));
  }
  writeStamp(stampPath, scope);
  if (previousVersion === null) {
    log(`Installed Fondue Claude Code skill (${CONSUMER_PACKAGE}@${FONDUE_VERSION}) → ${target}`);
  } else if (previousVersion === FONDUE_VERSION) {
    log(`Refreshed Fondue Claude Code skill at ${CONSUMER_PACKAGE}@${FONDUE_VERSION} → ${target}`);
  } else {
    log(
      `Updated Fondue Claude Code skill (${CONSUMER_PACKAGE}@${previousVersion} → @${FONDUE_VERSION}) → ${target}`
    );
  }
  log(scope === "project" ? "Scope: project (this directory only)." : "Scope: user (every project).");
  if (previousVersion === null) {
    log("");
    log("Next steps:");
    log(`  • Open Claude Code in a project that has \`${CONSUMER_PACKAGE}\` installed.`);
    log('  • Ask "what Fondue component should I use for X?" — Claude picks the skill up automatically,');
    log(`    or invoke it explicitly with /${SKILL_NAME}.`);
    if (scope === "project") {
      log(`  • Commit \`.claude/skills/${SKILL_NAME}/\` if you want it shared with your team.`);
    }
  }
};
const status = (options) => {
  const scope = scopeOf(options);
  const target = targetDirFor(scope);
  const stampPath = stampPathFor(scope);
  const targetExists = existsSync(target);
  const read = readStamp(stampPath);
  if (!targetExists && read.status === "missing") {
    log(`Not installed at ${target}.`);
    return;
  }
  if (read.status === "ok") {
    if (!targetExists) {
      log(`Stamp at ${stampPath} but skill directory is missing at ${target}.`);
      log("Run `fondue adapter install claude-skill` to repair.");
      return;
    }
    log(`Installed at ${target}`);
    log(`  package:     ${read.stamp.package}@${read.stamp.version}`);
    log(`  scope:       ${read.stamp.scope}`);
    log(`  installedAt: ${read.stamp.installedAt}`);
    return;
  }
  if (read.status === "corrupted") {
    log(`Stamp at ${stampPath} is unreadable (${read.error}).`);
    if (targetExists) {
      log(`Skill directory present at ${target}. Re-run install to repair, or pass --force.`);
    }
    return;
  }
  log(`Directory exists at ${target} but was not installed by this CLI.`);
};
const uninstall = (options) => {
  const scope = scopeOf(options);
  const target = targetDirFor(scope);
  const stampPath = stampPathFor(scope);
  const targetExists = existsSync(target);
  const stampExists = existsSync(stampPath);
  if (!targetExists && !stampExists) {
    log(`Nothing to uninstall — no skill at ${target}.`);
    return;
  }
  if (targetExists) {
    const read = readStamp(stampPath);
    if (read.status === "missing" && !options.force) {
      fail(`${target} exists but was not installed by this CLI. Remove it manually, or pass --force.`);
    }
    if (read.status === "corrupted" && !options.force) {
      fail(
        `Stamp file at ${stampPath} is unreadable (${read.error}). Inspect it, or pass --force to remove the skill and the stamp.`
      );
    }
    rmSync(target, { recursive: true, force: true });
  }
  if (stampExists) {
    rmSync(stampPath, { force: true });
  }
  log(`Removed ${target}.`);
};
const claudeSkill = {
  name: "claude-skill",
  description: "Claude Code skill — teaches Claude to query the Fondue SDK directly",
  install,
  uninstall,
  status
};
const ADAPTERS = [claudeSkill];
const adapterNames = () => ADAPTERS.map((i) => i.name).join(", ");
const adapterCatalog = () => {
  const width = Math.max(...ADAPTERS.map((i) => i.name.length));
  return ADAPTERS.map((i) => `  ${i.name.padEnd(width)}  ${i.description}`).join("\n");
};
const requireAdapter = (name, verb) => {
  if (name === void 0) {
    return fail(
      `Specify which adapter to ${verb}. Available:
${adapterCatalog()}

Example: fondue adapter ${verb} ${ADAPTERS[0]?.name ?? "<name>"}`
    );
  }
  const adapter2 = ADAPTERS.find((i) => i.name === name);
  if (adapter2 !== void 0) {
    return adapter2;
  }
  return fail(`Unknown adapter "${name}". Available: ${adapterNames()}.`);
};
const program = new Command().name("fondue").description("CLI for Frontify Fondue.").version("13.6.2");
const adapter = program.command("adapter").description("Install and manage Fondue SDK adapters (Claude Code skill, MCP, REST, …).");
adapter.command("install [name]").aliases(["add", "update"]).description(
  "Install an adapter, or refresh an existing install in place. Run `adapter list` to see what `<name>` accepts."
).option("--user", "Install for the current user instead of the current project").option("--force", "Overwrite a directory at the target path that was not installed by this CLI").action((name, options) => {
  requireAdapter(name, "install").install(options);
});
adapter.command("uninstall [name]").alias("remove").description("Uninstall an adapter previously installed by this CLI.").option("--user", "Target the user-scope install").option("--force", "Force removal even if not installed by this CLI").action((name, options) => {
  requireAdapter(name, "uninstall").uninstall(options);
});
adapter.command("status [name]").description("Show installation status for one adapter, or every adapter when no name is given.").option("--user", "Target the user-scope install").action((name, options) => {
  if (name !== void 0) {
    requireAdapter(name, "status").status(options);
    return;
  }
  for (const [index, registered] of ADAPTERS.entries()) {
    if (index > 0) {
      log("");
    }
    log(`[${registered.name}]`);
    registered.status(options);
  }
});
adapter.command("list").alias("ls").description("List every registered adapter and what it does.").action(() => {
  log(adapterCatalog());
});
program.parse();
