const MANIFEST_SCHEMA_VERSION = "2.0";

const ACTIONS = new Set(["created", "updated", "skipped", "conflict"]);
const SOURCES = new Set(["capint", "user"]);
const KINDS = new Set(["doc", "skill", "workflow", "matrix", "registry", "ide_projection"]);

function inferKindFromPath(relPath) {
  const p = relPath.replace(/\\/g, "/");
  if (p.startsWith("skills/")) return "skill";
  if (p.startsWith("workflows/")) return "workflow";
  if (p === "skill-routing-matrix.json") return "matrix";
  if (p === "registry.json") return "registry";
  if (
    p.includes(".cursor/rules/") ||
    p === "CLAUDE.md" ||
    p === "GEMINI.md" ||
    p.startsWith(".agents/")
  ) {
    return "ide_projection";
  }
  return "doc";
}

function defaultFileMeta(relPath, overrides = {}) {
  const kind = overrides.kind || inferKindFromPath(relPath);
  const source = overrides.source || "capint";
  const removable =
    typeof overrides.removable === "boolean"
      ? overrides.removable
      : source === "capint" && kind !== "doc";
  return {
    path: relPath.replace(/\\/g, "/"),
    source,
    removable,
    kind,
    marker: overrides.marker ?? null
  };
}

function enrichFileEntry(entry) {
  const pathNorm = (entry.path || "").replace(/\\/g, "/");
  const meta = defaultFileMeta(pathNorm, {
    source: entry.source,
    removable: entry.removable,
    kind: entry.kind,
    marker: entry.marker
  });
  return {
    path: pathNorm,
    action: entry.action,
    source: meta.source,
    removable: meta.removable,
    kind: meta.kind,
    marker: meta.marker,
    sidecar: entry.sidecar || null
  };
}

function validateManifest(manifest) {
  const errors = [];
  if (!manifest || typeof manifest !== "object") {
    return { valid: false, errors: ["manifest must be an object"] };
  }
  if (manifest.schema_version !== MANIFEST_SCHEMA_VERSION) {
    errors.push(`schema_version must be ${MANIFEST_SCHEMA_VERSION}`);
  }
  if (!Array.isArray(manifest.files)) {
    errors.push("files must be an array");
    return { valid: false, errors };
  }
  for (let i = 0; i < manifest.files.length; i++) {
    const f = manifest.files[i];
    if (!f.path || typeof f.path !== "string") errors.push(`files[${i}].path required`);
    if (!ACTIONS.has(f.action)) errors.push(`files[${i}].action invalid: ${f.action}`);
    if (!SOURCES.has(f.source)) errors.push(`files[${i}].source invalid: ${f.source}`);
    if (typeof f.removable !== "boolean") errors.push(`files[${i}].removable must be boolean`);
    if (!KINDS.has(f.kind)) errors.push(`files[${i}].kind invalid: ${f.kind}`);
  }
  return { valid: errors.length === 0, errors };
}

function buildManifestDocument({ report, previous = null }) {
  const files = (report.results || []).map(enrichFileEntry);
  const manifest = {
    schema_version: MANIFEST_SCHEMA_VERSION,
    last_run: report.generated_at,
    preset: report.preset,
    summary: report.summary,
    files,
    history: [
      ...(previous?.history || []).slice(-9),
      {
        at: report.generated_at,
        preset: report.preset,
        summary: report.summary
      }
    ]
  };
  const validation = validateManifest(manifest);
  if (!validation.valid) {
    throw new Error(`manifest validation failed: ${validation.errors.join("; ")}`);
  }
  return manifest;
}

module.exports = {
  MANIFEST_SCHEMA_VERSION,
  ACTIONS,
  SOURCES,
  KINDS,
  inferKindFromPath,
  defaultFileMeta,
  enrichFileEntry,
  validateManifest,
  buildManifestDocument
};
