#!/bin/sh
set -eu

CONTAINER="${1:-reactive-resume-reactive-resume-1}"

docker exec -u root -i "$CONTAINER" sh <<'SH'
set -eu

SSR_FILE="/app/apps/web/.output/server/_ssr/pdf-document-COfeOLVC.mjs"
SW_FILE="/app/apps/web/.output/public/sw.js"
SERVER_INDEX_FILE="/app/apps/web/.output/server/index.mjs"
SSR_RENDERER_FILE="/app/apps/web/.output/server/_chunks/ssr-renderer.mjs"

test -f "$SSR_FILE.bak-sw-cache" || cp "$SSR_FILE" "$SSR_FILE.bak-sw-cache" 2>/dev/null || true
test -f "$SW_FILE.bak-sw-cache" || cp "$SW_FILE" "$SW_FILE.bak-sw-cache" 2>/dev/null || true
test -f "$SERVER_INDEX_FILE.bak-sw-cache" || cp "$SERVER_INDEX_FILE" "$SERVER_INDEX_FILE.bak-sw-cache" 2>/dev/null || true
test -f "$SSR_RENDERER_FILE.bak-sw-cache" || cp "$SSR_RENDERER_FILE" "$SSR_RENDERER_FILE.bak-sw-cache" 2>/dev/null || true

node - <<'NODE'
const fs = require("fs");
const crypto = require("crypto");

const ssrFile = "/app/apps/web/.output/server/_ssr/pdf-document-COfeOLVC.mjs";
const swFile = "/app/apps/web/.output/public/sw.js";
const serverIndexFile = "/app/apps/web/.output/server/index.mjs";
const ssrRendererFile = "/app/apps/web/.output/server/_chunks/ssr-renderer.mjs";

const registrationScript = `
\t(() => {
\t\tif (!("serviceWorker" in navigator)) return;

\t\twindow.addEventListener("load", () => {
\t\t\tconst clearReactiveResumeCaches = async () => {
\t\t\t\tif ("caches" in window) {
\t\t\t\t\tconst keys = await caches.keys();
\t\t\t\t\tawait Promise.all(keys.map((key) => caches.delete(key)));
\t\t\t\t}

\t\t\t\tif (navigator.serviceWorker.getRegistrations) {
\t\t\t\t\tconst registrations = await navigator.serviceWorker.getRegistrations();
\t\t\t\t\tawait Promise.all(registrations.map((registration) => registration.unregister()));
\t\t\t\t}
\t\t\t};

\t\t\tclearReactiveResumeCaches().catch(console.error);
\t\t});
\t})();
`;

let ssr = fs.readFileSync(ssrFile, "utf8");
const start = "var pwaServiceWorkerRegistrationScript = `";
const end = "`;\nvar src_default =";
const startIndex = ssr.indexOf(start);
if (startIndex === -1) {
  throw new Error("Service worker registration script start marker not found");
}
const endIndex = ssr.indexOf(end, startIndex + start.length);
if (endIndex === -1) {
  throw new Error("Service worker registration script end marker not found");
}

ssr =
  ssr.slice(0, startIndex) +
  start +
  registrationScript +
  ssr.slice(endIndex);
fs.writeFileSync(ssrFile, ssr);

const sw = `self.addEventListener("install", () => {
  self.skipWaiting();
});

self.addEventListener("activate", (event) => {
  event.waitUntil((async () => {
    const keys = await caches.keys();
    await Promise.all(keys.map((key) => caches.delete(key)));
    await self.registration.unregister();
    await self.clients.claim();

    const clients = await self.clients.matchAll({
      type: "window",
      includeUncontrolled: true,
    });

    for (const client of clients) {
      client.postMessage({ type: "RR_SW_CACHE_CLEARED" });
    }
  })());
});

self.addEventListener("fetch", () => {});
`;
fs.writeFileSync(swFile, sw);

function makeEtag(buffer) {
  const digest = crypto.createHash("sha1").update(buffer).digest("base64").replace(/=+$/g, "");
  return `"${buffer.length.toString(16)}-${digest}"`;
}

function patchStaticManifestEntry(source, urlPath, filePath) {
  const buffer = fs.readFileSync(filePath);
  const startMarker = `"${urlPath}": {`;
  const start = source.indexOf(startMarker);
  if (start === -1) {
    throw new Error(`Static manifest entry not found for ${urlPath}`);
  }

  const end = source.indexOf("\n\t},", start);
  if (end === -1) {
    throw new Error(`Static manifest entry end not found for ${urlPath}`);
  }

  let entry = source.slice(start, end);
  entry = entry
    .replace(/"etag": "(?:\\.|[^"\\])*"/, `"etag": ${JSON.stringify(makeEtag(buffer))}`)
    .replace(/"mtime": "(?:\\.|[^"\\])*"/, `"mtime": ${JSON.stringify(new Date().toISOString())}`)
    .replace(/"size": \d+/, `"size": ${buffer.length}`);

  return source.slice(0, start) + entry + source.slice(end);
}

let serverIndex = fs.readFileSync(serverIndexFile, "utf8");
serverIndex = patchStaticManifestEntry(serverIndex, "/sw.js", swFile);
fs.writeFileSync(serverIndexFile, serverIndex);

let ssrRenderer = fs.readFileSync(ssrRendererFile, "utf8");
const ssrRendererOriginal = `function ssrRenderer({ req }) {
\treturn fetchViteEnv("ssr", req);
}`;
const ssrRendererPatched = `async function ssrRenderer(event) {
\tconst response = await fetchViteEnv("ssr", event.req);
\tconst headers = new Headers(response.headers);
\tconst accept = event.req.headers.get("accept") || "";

\tif (accept.includes("text/html")) {
\t\theaders.set("Cache-Control", "no-store, max-age=0");
\t\theaders.set("Pragma", "no-cache");
\t\theaders.set("Expires", "0");
\t}

\treturn new Response(response.body, {
\t\tstatus: response.status,
\t\tstatusText: response.statusText,
\t\theaders,
\t});
}`;
if (!ssrRenderer.includes(ssrRendererPatched)) {
  if (!ssrRenderer.includes(ssrRendererOriginal)) {
    throw new Error("SSR renderer marker not found");
  }

  ssrRenderer = ssrRenderer.replace(ssrRendererOriginal, ssrRendererPatched);
  fs.writeFileSync(ssrRendererFile, ssrRenderer);
}
NODE

node --check "$SSR_FILE" >/dev/null
node --check "$SW_FILE" >/dev/null
node --check "$SERVER_INDEX_FILE" >/dev/null
node --check "$SSR_RENDERER_FILE" >/dev/null
SH
