const WS_RETRY_MS = 1_000;

function refetchCSS(file) {
  const node = Array.from(document.head.childNodes).find(
    (n) => n.href && n.href.includes(file),
  );
  if (!node) {
    console.warn("Could not find node", file);
    console.log(Array.from(document.head.childNodes));
    return;
  }
  const url = new URL(node.href);
  url.searchParams.set("v", parseInt(url.searchParams.get("v") || "0") + 1);

  const n2 = node.cloneNode();
  n2.href = url.toString();
  document.head.appendChild(n2);
  setTimeout(() => {
    document.head.removeChild(node);
  }, 100);
}

let __file_to_module = {};
function refetchJS(file) {
  if (file in __file_to_module) {
    const o = __file_to_module[file];
    if ("__cleanup" in o) {
      o.__cleanup();
    } else {
      console.warn("no cleanup");
    }
  }
  import(`/static/${file}?v=${Date.now()}`)
    .then((m) => {
      __file_to_module[file] = m;
    })
    .catch((e) => {
      console.error(e);
    });
  return;
}

function connect() {
  console.log("try to connect through websocket");
  const ws = new WebSocket(`ws://${window.location.host}/dev-hr/ws`);

  const file2timeout = new Map();
  ws.addEventListener("message", (msg) => {
    const file = msg.data; // the path to a changed file relative to `static/`.
    if (file2timeout.has(file)) clearTimeout(file2timeout.get(file));
    file2timeout.set(
      file,
      setTimeout(() => {
        if (file.slice(-4) === ".css") refetchCSS(file);
        else if (file.slice(-3) === ".js") refetchJS(file);
        else console.warn("unknown file extension", file);
      }, 100),
    );
  });

  ws.addEventListener("open", () => {
    console.log("websocket connected");
  });

  ws.addEventListener("close", () => {
    console.log("websocket disconnected");
    setTimeout(() => {
      try {
        connect();
      } catch (e) {
        console.error(e);
      }
    }, WS_RETRY_MS);
  });

  ws.addEventListener("error", (e) => {
    console.error(e);
    ws.close();
  });
}
setTimeout(() => connect(), WS_RETRY_MS);
