const fs = require("fs");
const path = require("path");
const { CAPINT_SYNC_MARKER } = require("./ide-sync");
const { readScaffoldManifest } = require("./scaffold/manifest");

function isCapintMarked(filePath) {
  if (!fs.existsSync(filePath)) return false;
  try {
    return fs.readFileSync(filePath, "utf-8").includes(CAPINT_SYNC_MARKER);
  } catch {
    return false;
  }
}

function collectManifestRemovals(rootDir, manifest, options = {}) {
  const plan = [];
  const { keepAgent = false, keepIde = false, includeSidecars = false } = options;

  for (const entry of manifest?.files || []) {
    if (entry.source !== "capint" || !entry.removable) continue;
    if (entry.kind === "ide_projection" && keepIde) continue;
    if (entry.path === "AGENT.md" && keepAgent) continue;
    if (entry.path === "design.md" && keepAgent) continue;
    if (entry.path === "AGENTS.md" && keepAgent) continue;

    const abs = path.join(rootDir, entry.path);
    if (entry.kind === "ide_projection" && !isCapintMarked(abs)) continue;
    if (fs.existsSync(abs)) {
      plan.push({ path: entry.path, abs, type: "file", kind: entry.kind });
    }
  }

  if (includeSidecars) {
    for (const entry of manifest?.files || []) {
      if (entry.sidecar) {
        const abs = path.join(rootDir, entry.sidecar);
        if (fs.existsSync(abs)) plan.push({ path: entry.sidecar, abs, type: "sidecar" });
      }
    }
    for (const ent of fs.readdirSync(rootDir)) {
      if (ent.endsWith(".capint.new.md")) {
        plan.push({ path: ent, abs: path.join(rootDir, ent), type: "sidecar" });
      }
    }
  }

  const capintDir = path.join(rootDir, ".capint");
  if (fs.existsSync(capintDir)) {
    plan.push({ path: ".capint/", abs: capintDir, type: "dir" });
  }

  const seen = new Set();
  return plan.filter((p) => {
    if (seen.has(p.abs)) return false;
    seen.add(p.abs);
    return true;
  });
}

function collectIdeFallbackRemovals(rootDir, keepIde) {
  if (keepIde) return [];
  const candidates = [
    path.join(rootDir, ".cursor", "rules", "00-capint-session.mdc"),
    path.join(rootDir, "CLAUDE.md"),
    path.join(rootDir, "GEMINI.md"),
    path.join(rootDir, ".agents", "rules", "00-capint-session.md"),
    path.join(rootDir, ".agents", "CAPINT.md"),
    path.join(rootDir, ".agents", "skills", "capint-router", "SKILL.md")
  ];
  return candidates
    .filter((abs) => isCapintMarked(abs))
    .map((abs) => ({
      path: path.relative(rootDir, abs).replace(/\\/g, "/"),
      abs,
      type: "file",
      kind: "ide_projection"
    }));
}

function buildUninstallPlan(rootDir, options = {}) {
  const manifest = readScaffoldManifest(rootDir);
  const fromManifest = manifest
    ? collectManifestRemovals(rootDir, manifest, options)
    : [];
  const fromIde = collectIdeFallbackRemovals(rootDir, options.keepIde);
  const merged = [...fromManifest, ...fromIde];
  const seen = new Set();
  return merged.filter((p) => {
    if (seen.has(p.abs)) return false;
    seen.add(p.abs);
    return true;
  });
}

function removePath(entry) {
  if (entry.type === "dir") {
    fs.rmSync(entry.abs, { recursive: true, force: true });
    return;
  }
  fs.rmSync(entry.abs, { force: true });
}

function executeUninstall(rootDir, plan, dryRun) {
  const removed = [];
  const skipped = [];
  for (const entry of plan) {
    if (!fs.existsSync(entry.abs)) {
      skipped.push(entry.path);
      continue;
    }
    if (entry.kind === "ide_projection" && !isCapintMarked(entry.abs)) {
      skipped.push(entry.path);
      continue;
    }
    if (!dryRun) removePath(entry);
    removed.push(entry.path);
  }
  return { removed, skipped };
}

module.exports = {
  buildUninstallPlan,
  executeUninstall,
  isCapintMarked,
  collectManifestRemovals
};
