const overlay = document.createElement("section");
overlay.className = "error-overlay";
overlay.hidden = true;
overlay.innerHTML = `
  <div class="error-overlay-header">
    <strong>JavaScript error</strong>
    <div class="error-overlay-actions">
      <button type="button" data-action="copy">Copy</button>
      <button type="button" data-action="dismiss" aria-label="Dismiss error">Dismiss</button>
    </div>
  </div>
  <pre></pre>
`;

const messageNode = overlay.querySelector("pre");
const copyButton = overlay.querySelector("[data-action='copy']");
const dismissButton = overlay.querySelector("[data-action='dismiss']");

copyButton.addEventListener("click", async () => {
  await copyText(messageNode.textContent);
  showCopyStatus();
});

dismissButton.addEventListener("click", () => {
  overlay.hidden = true;
});

document.addEventListener("DOMContentLoaded", () => {
  document.body.append(overlay);
});

window.addEventListener("error", (event) => {
  showError(formatErrorEvent(event));
});

window.addEventListener("unhandledrejection", (event) => {
  showError(formatReason(event.reason));
});

function showError(message) {
  messageNode.textContent = message;
  copyButton.textContent = "Copy";
  overlay.hidden = false;
}

async function copyText(value) {
  if (navigator.clipboard?.writeText) {
    await navigator.clipboard.writeText(value);
    return;
  }

  const textArea = document.createElement("textarea");
  textArea.value = value;
  textArea.setAttribute("readonly", "");
  textArea.className = "error-overlay-copy-buffer";
  document.body.append(textArea);
  textArea.select();
  document.execCommand("copy");
  textArea.remove();
}

function showCopyStatus() {
  copyButton.textContent = "Copied";

  window.setTimeout(() => {
    copyButton.textContent = "Copy";
  }, 1400);
}

function formatErrorEvent(event) {
  const location = [event.filename, event.lineno, event.colno].filter(Boolean).join(":");
  const detail = formatReason(event.error ?? event.message);
  return location ? `${detail}\n\n${location}` : detail;
}

function formatReason(reason) {
  if (reason instanceof Error) {
    return reason.stack ?? `${reason.name}: ${reason.message}`;
  }

  return String(reason);
}
