import fs from "node:fs";
import path from "node:path";

const distDir = path.resolve("dist");

function walk(dir) {
  const entries = fs.readdirSync(dir, { withFileTypes: true });
  const files = [];

  for (const entry of entries) {
    const full = path.join(dir, entry.name);
    if (entry.isDirectory()) files.push(...walk(full));
    else if (entry.isFile() && full.endsWith(".html")) files.push(full);
  }

  return files;
}

function getPrefixToDistRoot(file) {
  const relative = path.relative(path.dirname(file), distDir).replaceAll("\\", "/");
  return relative === "" ? "./" : `${relative}/`;
}

function escapeRegExp(value) {
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}

function rewriteRootedAsset(html, attr, rootName, prefix) {
  const target = `${prefix}${rootName}/`;

  return html
    // Fresh Astro output: href="/_astro/..."
    .replace(new RegExp(`(${attr})="/${escapeRegExp(rootName)}/`, "g"), `$1="${target}`)
    // Already USB-rewritten root page form: href="./_astro/..."
    .replace(new RegExp(`(${attr})="\\./${escapeRegExp(rootName)}/`, "g"), `$1="${target}`);
}

function rewriteHtml(html, file) {
  const prefix = getPrefixToDistRoot(file);

  let out = html;

  // CSS/JS/assets generated by Astro and public assets.
  for (const attr of ["href", "src"]) {
    for (const rootName of ["_astro", "images", "files", "demos", "source"]) {
      out = rewriteRootedAsset(out, attr, rootName, prefix);
    }
  }

  // Homepage.
  out = out
    .replace(/href="\/"/g, `href="${prefix}index.html"`)
    .replace(/href="\.\/index\.html"/g, `href="${prefix}index.html"`);

  // Directory-style internal links -> flat html links.
  // Examples:
  //   /foo/      -> ./foo.html      from dist/foo.html
  //   /foo/      -> ../foo.html     from dist/en/bar.html
  //   /en/foo/   -> ../en/foo.html  from dist/en/bar.html
  out = out.replace(/href="\/([^"?#]+?)\/"/g, (_match, slug) => {
    return `href="${prefix}${slug}.html"`;
  });

  // Any remaining root-relative href/src points to a file or asset that was
  // not covered above, for example /SHA256SUMS.txt or /keys/public-key.asc.
  // Convert it relative to the current HTML file so the build remains
  // portable when opened through file:// from any directory or drive.
  for (const attr of ["href", "src"]) {
    out = out.replace(
      new RegExp(`(${attr})="/(?!/)([^"]+)"`, "g"),
      `$1="${prefix}$2"`,
    );
  }

  return out;
}

const htmlFiles = walk(distDir);

for (const file of htmlFiles) {
  const original = fs.readFileSync(file, "utf8");
  const rewritten = rewriteHtml(original, file);
  fs.writeFileSync(file, rewritten, "utf8");
}

console.log(`Rewritten ${htmlFiles.length} HTML files for USB mode.`);
