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

const repoRoot = path.resolve(__dirname, "..");
const mealsPath = path.join(repoRoot, "data", "meals.json");
const indexTemplatePath = path.join(repoRoot, "templates", "index.html");
const indexOutputPath = path.join(repoRoot, "index.html");

function detectEol(text) {
  return text.includes("\r\n") ? "\r\n" : "\n";
}

function escapeHtml(value) {
  return value
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/"/g, "&quot;");
}

function validateMeals(meals) {
  if (!Array.isArray(meals)) {
    throw new Error("data/meals.json must contain an array");
  }

  for (const [index, meal] of meals.entries()) {
    if (!meal || typeof meal !== "object") {
      throw new Error(`Meal at index ${index} must be an object`);
    }

    for (const field of ["id", "title", "description"]) {
      if (typeof meal[field] !== "string" || meal[field].length === 0) {
        throw new Error(`Meal ${index} is missing required string field "${field}"`);
      }
    }

    if (meal.position !== undefined && typeof meal.position !== "string") {
      throw new Error(`Meal ${index} has a non-string "position" value`);
    }
  }
}

function renderGalleryItem(meal, eol) {
  const attrs = [`class="thumbnail"`, `href="images/fulls/${meal.id}.jpg"`];

  if (meal.position) {
    attrs.push(`data-position="${escapeHtml(meal.position)}"`);
  }

  return [
    "\t\t\t\t<article>",
    `\t\t\t\t\t<a ${attrs.join(" ")}><img src="images/thumbs/${meal.id}.jpg" alt="" /></a>`,
    `\t\t\t\t\t<h2>${escapeHtml(meal.title)}</h2>`,
    `\t\t\t\t\t<p>${escapeHtml(meal.description)}</p>`,
    "\t\t\t\t</article>",
  ].join(eol);
}

function renderGallery(meals, eol) {
  return meals.map((meal) => renderGalleryItem(meal, eol)).join(eol);
}

function replaceBlock(template, token, replacement) {
  const pattern = new RegExp(`^[\\t ]*\\{\\{${token}\\}\\}$`, "m");

  if (!pattern.test(template)) {
    throw new Error(`Template is missing required block token "{{${token}}}"`);
  }

  return template.replace(pattern, () => replacement);
}

function buildIndex() {
  const template = fs.readFileSync(indexTemplatePath, "utf8");
  const eol = detectEol(template);
  const meals = JSON.parse(fs.readFileSync(mealsPath, "utf8"));

  validateMeals(meals);

  return replaceBlock(template, "gallery_items", renderGallery(meals, eol));
}

function writeFile(filePath, contents) {
  fs.writeFileSync(filePath, contents);
}

function main() {
  writeFile(indexOutputPath, buildIndex());
}

main();
