/**
 * IDE projection sync — capint/projections/session-start.md → native IDE entry files.
 */

const fs = require("fs");
const path = require("path");

const DEFAULT_TARGETS = ["cursor", "claude", "gemini", "antigravity"];

const CAPINT_SYNC_MARKER =
  "<!-- source: capint/projections/session-start.md | capint ide sync -->";

function pkgRoot() {
  return path.join(__dirname, "..", "..");
}

function readSessionStart() {
  const p = path.join(pkgRoot(), "projections", "session-start.md");
  if (!fs.existsSync(p)) return null;
  return fs.readFileSync(p, "utf-8");
}

function stripFrontmatter(text) {
  if (!text.startsWith("---")) return text;
  const end = text.indexOf("---", 3);
  if (end === -1) return text;
  return text.slice(end + 3).trimStart();
}

function syncCursorRule(cwd, body, dryRun) {
  const dir = path.join(cwd, ".cursor", "rules");
  const file = path.join(dir, "00-capint-session.mdc");
  const content = `---
description: CapInt session start + Execution Intent (always apply)
alwaysApply: true
---

${CAPINT_SYNC_MARKER}

${body}
`;
  if (!dryRun) {
    fs.mkdirSync(dir, { recursive: true });
    fs.writeFileSync(file, content);
  }
  return file;
}

function syncClaudeMd(cwd, body, dryRun) {
  const file = path.join(cwd, "CLAUDE.md");
  const content = `${CAPINT_SYNC_MARKER}

# Claude Code — CapInt

Read root **AGENT.md** for project rules.

${body}
`;
  if (!dryRun) fs.writeFileSync(file, content);
  return file;
}

function syncGeminiMd(cwd, body, dryRun) {
  const file = path.join(cwd, "GEMINI.md");
  const content = `${CAPINT_SYNC_MARKER}

# Gemini — CapInt

Read root **AGENT.md** for project rules.

${body}
`;
  if (!dryRun) fs.writeFileSync(file, content);
  return file;
}

function syncAntigravity(cwd, body, dryRun) {
  const written = [];
  const agentsDir = path.join(cwd, ".agents");
  const rulesDir = path.join(agentsDir, "rules");
  const skillsDir = path.join(agentsDir, "skills", "capint-router");

  const sessionBody = stripFrontmatter(body);
  const sessionFile = path.join(rulesDir, "00-capint-session.md");
  const indexFile = path.join(agentsDir, "CAPINT.md");
  const routerSkill = path.join(skillsDir, "SKILL.md");

  const sessionContent = `${CAPINT_SYNC_MARKER}

# CapInt session + task routing

${sessionBody}
`;
  const indexContent = `${CAPINT_SYNC_MARKER}

# CapInt

Canonical project files: \`AGENT.md\`, \`.capint/\` — run \`capint ide sync\` after init.
`;
  const routerContent = `---
name: capint-router
description: Routes agent to CapInt session protocol, skill gateway, and skill-routing-matrix.json.
origin: capint
capint_bundle: antigravity-projection
---

# CapInt Router (Antigravity)

1. Session: \`.agents/rules/00-capint-session.md\` + \`AGENT.md\`
2. Gateway: \`skills/prismx-skill-gateway/SKILL.md\` — read before coding/design tasks
3. Task routing: \`capint route "your task"\` + \`skills/task-skill-router/SKILL.md\`
4. Skills: \`skills/<name>/SKILL.md\` (full bundle installed at init)

Index: \`.agents/CAPINT.md\`
`;

  if (!dryRun) {
    fs.mkdirSync(rulesDir, { recursive: true });
    fs.mkdirSync(skillsDir, { recursive: true });
    fs.writeFileSync(sessionFile, sessionContent);
    fs.writeFileSync(indexFile, indexContent);
    fs.writeFileSync(routerSkill, routerContent);
  }

  written.push(sessionFile, indexFile, routerSkill);
  return written;
}

function updateContextJson(cwd, targets, dryRun) {
  const file = path.join(cwd, ".capint", "context.json");
  if (!fs.existsSync(file)) return null;
  let ctx;
  try {
    ctx = JSON.parse(fs.readFileSync(file, "utf-8"));
  } catch {
    return null;
  }
  ctx.ide_projection = {
    targets: [...targets],
    last_synced: new Date().toISOString().slice(0, 10),
    canonical: "capint/projections/session-start.md",
    marker: CAPINT_SYNC_MARKER
  };
  if (!dryRun) fs.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}\n`);
  return file;
}

function syncIdeProjections(cwd, options = {}) {
  const { targets = DEFAULT_TARGETS, dryRun = false } = options;
  const result = { written: [], skipped: [], errors: [] };

  const capintDir = path.join(cwd, ".capint");
  if (!fs.existsSync(capintDir) && !fs.existsSync(path.join(cwd, "AGENT.md"))) {
    result.errors.push("No CapInt project — run capint init first");
    return result;
  }

  const raw = readSessionStart();
  if (!raw) {
    result.errors.push("session-start.md not found in package projections/");
    return result;
  }
  const body = stripFrontmatter(raw);
  const set = new Set(targets.map((t) => t.toLowerCase()));

  if (set.has("cursor")) result.written.push(syncCursorRule(cwd, body, dryRun));
  if (set.has("claude") || set.has("claude-code")) {
    result.written.push(syncClaudeMd(cwd, body, dryRun));
  }
  if (set.has("gemini") || set.has("gemini-cli")) {
    result.written.push(syncGeminiMd(cwd, body, dryRun));
  }
  if (set.has("codex")) {
    result.skipped.push("codex uses root AGENTS.md — ensure AGENTS.md exists");
  }
  if (set.has("antigravity")) {
    result.written.push(...syncAntigravity(cwd, body, dryRun));
  }

  const ctxPath = updateContextJson(cwd, [...set], dryRun);
  if (ctxPath) result.written.push(ctxPath);

  return result;
}

function checkIdeProjection(cwd) {
  const marker = CAPINT_SYNC_MARKER;
  function hasMarker(filePath) {
    if (!fs.existsSync(filePath)) return false;
    return fs.readFileSync(filePath, "utf-8").includes(marker);
  }

  return [
    {
      name: "Cursor .mdc",
      ok: hasMarker(path.join(cwd, ".cursor", "rules", "00-capint-session.mdc")),
      path: ".cursor/rules/00-capint-session.mdc"
    },
    { name: "CLAUDE.md", ok: hasMarker(path.join(cwd, "CLAUDE.md")), path: "CLAUDE.md" },
    { name: "GEMINI.md", ok: hasMarker(path.join(cwd, "GEMINI.md")), path: "GEMINI.md" },
    {
      name: "Antigravity session",
      ok: hasMarker(path.join(cwd, ".agents", "rules", "00-capint-session.md")),
      path: ".agents/rules/00-capint-session.md"
    },
    {
      name: "AGENTS.md",
      ok: fs.existsSync(path.join(cwd, "AGENTS.md")),
      path: "AGENTS.md"
    },
    {
      name: "skill-routing-matrix.json",
      ok: fs.existsSync(path.join(cwd, "skill-routing-matrix.json")),
      path: "skill-routing-matrix.json"
    }
  ];
}

function appendIdeManifestEntries(rootDir, syncResult, dryRun) {
  if (dryRun) return null;
  const { readScaffoldManifest, writeScaffoldManifest } = require("./scaffold/manifest");
  const { enrichFileEntry } = require("./scaffold/manifest-schema");

  const manifestPath = path.join(rootDir, ".capint", "scaffold-manifest.json");
  if (!fs.existsSync(manifestPath)) return null;

  let manifest;
  try {
    manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
  } catch {
    return null;
  }

  const existing = new Set((manifest.files || []).map((f) => f.path));
  const relPaths = syncResult.written.map((abs) =>
    path.relative(rootDir, abs).replace(/\\/g, "/")
  );

  for (const rel of relPaths) {
    if (existing.has(rel)) continue;
    manifest.files.push(
      enrichFileEntry({
        path: rel,
        action: "created",
        source: "capint",
        removable: true,
        kind: "ide_projection",
        marker: CAPINT_SYNC_MARKER
      })
    );
  }

  manifest.last_run = new Date().toISOString();
  const report = {
    generated_at: manifest.last_run,
    preset: manifest.preset,
    summary: manifest.summary,
    results: manifest.files.map((f) => ({
      path: f.path,
      action: f.action,
      source: f.source,
      removable: f.removable,
      kind: f.kind,
      marker: f.marker,
      sidecar: f.sidecar
    }))
  };
  writeScaffoldManifest(rootDir, report);
  return manifestPath;
}

module.exports = {
  DEFAULT_TARGETS,
  CAPINT_SYNC_MARKER,
  syncIdeProjections,
  checkIdeProjection,
  appendIdeManifestEntries
};
