const fs = require("fs");
const path = require("path");
const { deriveRegistryFromMatrix, copyBundle, listPackageSkillNames, pkgRoot } = require("./scaffold/presets");

function loadJson(filePath) {
  return JSON.parse(fs.readFileSync(filePath, "utf-8"));
}

function taskTypeIds(matrix) {
  return new Set((matrix?.task_types || []).map((t) => t.id));
}

function mergeTaskTypes(packageMatrix, projectMatrix) {
  const conflicts = [];
  const customPreserved = [];
  const pkgById = new Map((packageMatrix.task_types || []).map((t) => [t.id, t]));
  const projById = new Map((projectMatrix.task_types || []).map((t) => [t.id, t]));

  for (const [id, proj] of projById) {
    if (!pkgById.has(id)) {
      customPreserved.push(id);
    }
  }

  const merged = [];
  for (const pkgTt of packageMatrix.task_types || []) {
    const projTt = projById.get(pkgTt.id);
    if (!projTt) {
      merged.push(structuredClone(pkgTt));
      continue;
    }
    const out = structuredClone(pkgTt);
    for (const key of Object.keys(projTt)) {
      if (key === "id") continue;
      const pv = projTt[key];
      const pkgv = pkgTt[key];
      if (JSON.stringify(pv) !== JSON.stringify(pkgv)) {
        conflicts.push({
          id: pkgTt.id,
          field: key,
          project_value: pv,
          package_value: pkgv,
          resolution: "package_wins"
        });
      }
    }
    merged.push(out);
  }

  for (const id of customPreserved) {
    merged.push(structuredClone(projById.get(id)));
  }

  return { merged, conflicts, custom_preserved: customPreserved };
}

function mergeMatrices(packageMatrix, projectMatrix) {
  const topKeys = new Set([...Object.keys(packageMatrix), ...Object.keys(projectMatrix)]);
  const conflicts = [];
  const result = structuredClone(packageMatrix);

  for (const key of topKeys) {
    if (key === "task_types") continue;
    if (!(key in projectMatrix)) continue;
    if (JSON.stringify(projectMatrix[key]) !== JSON.stringify(packageMatrix[key])) {
      conflicts.push({
        id: "_top_level",
        field: key,
        project_value: projectMatrix[key],
        package_value: packageMatrix[key],
        resolution: "package_wins"
      });
    }
  }

  const tt = mergeTaskTypes(packageMatrix, projectMatrix);
  result.task_types = tt.merged;
  return {
    merged: result,
    conflicts: [...conflicts, ...tt.conflicts],
    custom_preserved: tt.custom_preserved
  };
}

function planUpgrade(rootDir, packageRoot) {
  const projectPath = path.join(rootDir, "skill-routing-matrix.json");
  const packagePath = path.join(packageRoot, "skill-routing-matrix.json");

  if (!fs.existsSync(projectPath)) {
    return { error: "skill-routing-matrix.json not found in project" };
  }
  if (!fs.existsSync(packagePath)) {
    return { error: "package skill-routing-matrix.json not found" };
  }

  const projectMatrix = loadJson(projectPath);
  const packageMatrix = loadJson(packagePath);
  const { merged, conflicts, custom_preserved } = mergeMatrices(packageMatrix, projectMatrix);

  return {
    project_schema: projectMatrix.schema_version,
    package_schema: packageMatrix.schema_version,
    conflicts,
    custom_preserved,
    merged,
    summary: `${conflicts.length} conflicts — package wins; review before --apply`
  };
}

function applyUpgrade(rootDir, merged, packageRoot = pkgRoot()) {
  const projectPath = path.join(rootDir, "skill-routing-matrix.json");
  const backupDir = path.join(rootDir, ".capint", "backups");
  fs.mkdirSync(backupDir, { recursive: true });
  const stamp = new Date().toISOString().replace(/[:.]/g, "-");
  const backupPath = path.join(backupDir, `skill-routing-matrix.${stamp}.json`);
  fs.copyFileSync(projectPath, backupPath);
  fs.writeFileSync(projectPath, `${JSON.stringify(merged, null, 2)}\n`, "utf-8");

  const registryPath = path.join(rootDir, "registry.json");
  if (fs.existsSync(registryPath)) {
    const registryBackup = path.join(backupDir, `registry.${stamp}.json`);
    fs.copyFileSync(registryPath, registryBackup);
  }
  fs.writeFileSync(
    registryPath,
    `${JSON.stringify(deriveRegistryFromMatrix(merged, packageRoot), null, 2)}\n`,
    "utf-8"
  );

  copyBundle({ rootDir, force: false });

  return backupPath;
}

module.exports = { planUpgrade, applyUpgrade, mergeMatrices };
