import { copyFile, readdir, readFile, writeFile } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { zipSync } from "fflate";

const projectRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const outputPath = path.join(projectRoot, "public", "source.zip");
const noticesPath = path.join(projectRoot, "public", "THIRD_PARTY_NOTICES.md");
const fixedTimestamp = new Date("2026-01-01T00:00:00.000Z");
const excludedDirectories = new Set([
  ".git",
  ".git.site-starter-backup",
  ".next",
  ".vinext",
  ".wrangler",
  "coverage",
  "dist",
  "node_modules",
  "outputs",
  "work",
]);

function shouldExclude(relativePath, entry) {
  const normalized = relativePath.replaceAll("\\", "/");
  if (entry.isDirectory() && excludedDirectories.has(entry.name)) return true;
  if (normalized === "public/source.zip" || normalized === "public/THIRD_PARTY_NOTICES.md") return true;
  if (entry.name === ".DS_Store" || entry.name.endsWith(".tsbuildinfo")) return true;
  if (entry.name === ".env" || entry.name.startsWith(".env.")) return true;
  return false;
}

async function collect(directory, entries) {
  const children = await readdir(directory, { withFileTypes: true });
  children.sort((left, right) => left.name.localeCompare(right.name, "en"));
  for (const entry of children) {
    const absolutePath = path.join(directory, entry.name);
    const relativePath = path.relative(projectRoot, absolutePath).replaceAll("\\", "/");
    if (shouldExclude(relativePath, entry)) continue;
    if (entry.isDirectory()) {
      await collect(absolutePath, entries);
    } else if (entry.isFile()) {
      entries[`hearbooks/${relativePath}`] = [
        new Uint8Array(await readFile(absolutePath)),
        { mtime: fixedTimestamp },
      ];
    }
  }
}

const entries = {};
await copyFile(path.join(projectRoot, "THIRD_PARTY_NOTICES.md"), noticesPath);
await collect(projectRoot, entries);
await writeFile(outputPath, zipSync(entries, { level: 9 }));
console.log(`Packaged ${Object.keys(entries).length} source files.`);
