import fs from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";

const projectRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const data = JSON.parse(await fs.readFile(path.join(projectRoot, "app/quiz-data.json"), "utf8"));
const layout = JSON.parse(await fs.readFile(path.join(projectRoot, "app/tree-layout.json"), "utf8"));
const outputDir = path.join(projectRoot, "public/data");

function expectedTreeKeys(rootId) {
  const keys = new Set();

  function walk(questionId) {
    const questionKey = `question:${questionId}`;
    if (keys.has(questionKey)) throw new Error(`Tree layout requires one parent per question: ${questionId}`);
    keys.add(questionKey);
    for (const choice of data.graph[questionId].choices) {
      if (choice.type === "question") {
        walk(choice.id);
      } else {
        const resultKey = `result:${choice.ideology}`;
        if (keys.has(resultKey)) throw new Error(`Duplicate result in tree layout: ${choice.ideology}`);
        keys.add(resultKey);
      }
    }
  }

  walk(rootId);
  return keys;
}

function validateLayout(branch, rootId) {
  const branchLayout = layout[branch];
  if (!branchLayout || !Number.isInteger(branchLayout.width) || !Number.isInteger(branchLayout.height)) {
    throw new Error(`Invalid ${branch} tree dimensions`);
  }

  const expected = expectedTreeKeys(rootId);
  const byKey = new Map();
  const coordinates = new Set();
  for (const cell of branchLayout.cells) {
    if (byKey.has(cell.key)) throw new Error(`Duplicate ${branch} tree node: ${cell.key}`);
    if (cell.column < 0 || cell.row < 0 || cell.column >= branchLayout.width || cell.row >= branchLayout.height) {
      throw new Error(`Out-of-bounds ${branch} tree node: ${cell.key}`);
    }
    const coordinate = `${cell.column},${cell.row}`;
    if (coordinates.has(coordinate)) throw new Error(`Duplicate ${branch} tree coordinate: ${coordinate}`);
    byKey.set(cell.key, cell);
    coordinates.add(coordinate);
  }

  if (byKey.size !== expected.size || [...expected].some((key) => !byKey.has(key))) {
    throw new Error(`${branch} tree does not cover its complete result path`);
  }
  if (!byKey.get(`question:${rootId}`)?.start) throw new Error(`${branch} tree has no marked root`);

  for (const cell of branchLayout.cells.filter((item) => item.type === "question")) {
    for (const choice of data.graph[cell.id].choices) {
      const targetKey = choice.type === "question" ? `question:${choice.id}` : `result:${choice.ideology}`;
      const target = byKey.get(targetKey);
      const dx = Math.abs(target.column - cell.column);
      const dy = Math.abs(target.row - cell.row);
      if (dx > 1 || dy > 1 || dx + dy === 0) {
        throw new Error(`Non-adjacent ${branch} tree edge: ${cell.key} -> ${targetKey}`);
      }
    }
  }
}

validateLayout("pro", "q_constitution");
validateLayout("anti", "q_markets");

await fs.mkdir(outputDir, { recursive: true });
await Promise.all([
  fs.writeFile(path.join(outputDir, "quiz-data.json"), JSON.stringify(data)),
  fs.writeFile(path.join(outputDir, "tree-layout.json"), JSON.stringify(layout)),
]);

console.log(JSON.stringify({
  quizBytes: Buffer.byteLength(JSON.stringify(data)),
  treeBytes: Buffer.byteLength(JSON.stringify(layout)),
  pro: { width: layout.pro.width, height: layout.pro.height, cells: layout.pro.cells.length },
  anti: { width: layout.anti.width, height: layout.anti.height, cells: layout.anti.cells.length },
}));
