import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
import { extname, resolve } from "node:path";
import { fileURLToPath } from "node:url";

const projectRoot = resolve(fileURLToPath(new URL("..", import.meta.url)));
const outputDirectory = resolve(projectRoot, "strato-dist");
const localeMeta = JSON.parse(
  readFileSync(resolve(projectRoot, "app/data/public-locales.json"), "utf8"),
);
const locales = Object.keys(localeMeta);

function filesBelow(directory) {
  return readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
    const path = resolve(directory, entry.name);
    return entry.isDirectory() ? filesBelow(path) : [path];
  });
}

function requireFile(relativePath) {
  const path = resolve(outputDirectory, relativePath);
  if (!existsSync(path) || !statSync(path).isFile()) {
    throw new Error(`Missing STRATO file: ${relativePath}`);
  }
  return readFileSync(path, "utf8");
}

const root = requireFile("index.html");
const pages = Object.fromEntries(
  locales.map((locale) => [locale, requireFile(`${locale}/index.html`)]),
);
const robots = requireFile("robots.txt");
const sitemap = requireFile("sitemap.xml");
requireFile(".htaccess");
requireFile("privacy.html");
requireFile("legal.html");
const licensePage = requireFile("license.html");
const noticesPage = requireFile("third-party-notices.html");
requireFile("legal-doc.css");
requireFile("LICENSE.txt");
requireFile("THIRD_PARTY_NOTICES.txt");
requireFile("favicon.svg");

if (!root.includes('url=/en/') || !root.includes('content="noindex, follow"')) {
  throw new Error("STRATO verification failed: root must redirect to /en/.");
}

for (const locale of locales) {
  const page = pages[locale];
  const meta = localeMeta[locale];
  const canonical = `https://factoriocalculatorapp.com${meta.path}`;
  const assertions = [
    [page.includes(`lang="${locale}"`), `${locale} language marker`],
    [page.includes(meta.title), `${locale} title`],
    [page.includes(meta.description), `${locale} description`],
    [page.includes(`rel="canonical" href="${canonical}"`), `${locale} canonical URL`],
    [page.includes('<div id="root"><') && page.includes('<main class="app-shell"'), `${locale} pre-rendered calculator`],
    [page.includes('class="calculator-stage"'), `${locale} fixed-layout stage`],
  ];
  for (const alternate of locales) {
    assertions.push([
      page.includes(
        `hreflang="${alternate}" href="https://factoriocalculatorapp.com${localeMeta[alternate].path}"`,
      ),
      `${locale} → ${alternate} hreflang`,
    ]);
  }
  assertions.push([
    page.includes(
      'hreflang="x-default" href="https://factoriocalculatorapp.com/en/"',
    ),
    `${locale} x-default hreflang`,
  ]);
  for (const [condition, label] of assertions) {
    if (!condition) throw new Error(`STRATO verification failed: ${label}`);
  }
}

for (const [condition, label] of [
  [robots.includes("Allow: /"), "robots indexing rule"],
  [robots.includes("https://factoriocalculatorapp.com/sitemap.xml"), "robots sitemap"],
  [sitemap.includes("https://factoriocalculatorapp.com/en/"), "English sitemap URL"],
  [sitemap.includes("https://factoriocalculatorapp.com/zh-TW/"), "Traditional Chinese sitemap URL"],
  [sitemap.includes("https://factoriocalculatorapp.com/license.html"), "License sitemap URL"],
  [sitemap.includes("https://factoriocalculatorapp.com/third-party-notices.html"), "Notices sitemap URL"],
  [licensePage.includes("GNU GENERAL PUBLIC LICENSE"), "Styled complete GPL page"],
  [noticesPage.includes("Direct runtime packages"), "Styled third-party notices page"],
  [pages.en.includes('href="/license.html"'), "Styled license footer link"],
  [pages.en.includes('href="/third-party-notices.html"'), "Styled notices footer link"],
]) {
  if (!condition) throw new Error(`STRATO verification failed: ${label}`);
}

const allFiles = filesBelow(outputDirectory);
const textExtensions = new Set([
  ".css",
  ".html",
  ".js",
  ".json",
  ".mjs",
  ".svg",
  ".txt",
  ".xml",
]);
const publicText = allFiles
  .filter((path) => textExtensions.has(extname(path)))
  .map((path) => readFileSync(path, "utf8"))
  .join("\n");

for (const forbidden of [
  ["Florian", "Thomas"].join(" "),
  ["app", "gprj_"].join(""),
  ["PUBLIC", "RELEASE", "INPUTS"].join("_"),
  ["PERMISSION", "RECORD"].join("_"),
  ["private", "preview"].join(" "),
  ["Blueprint generator", "development build"].join(" "),
  ["Private", "Entwicklungsfassung"].join(" "),
  ["Optimized Biolab mode", "forms one continuous row"].join(" "),
]) {
  if (publicText.includes(forbidden)) {
    throw new Error(`Public build contains forbidden text: ${forbidden}`);
  }
}

const localeDirectories = new Set(locales.map((locale) => `/${locale}/`));
for (const html of Object.values(pages)) {
  for (const match of html.matchAll(/(?:src|href)="(\/[^"?#]*)/g)) {
    const reference = match[1];
    if (reference === "/" || localeDirectories.has(reference)) continue;
    if (reference === "/downloads/factorio-calculator-source-1.0.0.zip") {
      continue;
    }
    const localPath = resolve(outputDirectory, reference.slice(1));
    if (!existsSync(localPath)) {
      throw new Error(`Broken local reference: ${reference}`);
    }
  }
}

console.log(
  `STRATO verification passed: ${locales.length} locale pages, ${allFiles.length} files.`,
);

if (process.argv.includes("--release")) {
  const sourcePath = resolve(outputDirectory, "downloads/factorio-calculator-source-1.0.0.zip");
  if (!existsSync(sourcePath) || statSync(sourcePath).size < 100_000) {
    throw new Error("The release must include the complete corresponding source download.");
  }
  const operator = JSON.parse(readFileSync(resolve(projectRoot, "release-operator.json"), "utf8"));
  for (const pageName of ["legal.html", "privacy.html"]) {
    const html = requireFile(pageName);
    if (!html.includes(operator.name) || !html.includes(operator.city)) {
      throw new Error(`Missing approved operator information in ${pageName}.`);
    }
  }
  if (!publicText.includes("Blueprint export") || publicText.includes("__factorio_asset__")) {
    throw new Error("Expected the complete symbolic Blueprint generator in the public client build.");
  }
  if (!noticesPage.includes("react-remove-scroll-bar") || !noticesPage.includes("Copyright")) {
    throw new Error("The website must include full transitive client license notices.");
  }
  console.log("Release source, operator details, generator and transitive notices verified.");
}
