import { WaitingForInit } from "@src/components/WaitingForInit";
import { isServer } from "@src/utils";
import { createRoot, Root } from "react-dom/client";
import CSS from "../components/global.css";
import { fontDefinitions } from "./fonts";

export let xpayRoot: Root | null = null;
export let xpayShadowRoot: ShadowRoot | null = null;
export let xpayInitIndicatorRoot: Root | null = null;
export let xpayTxStatusRoot: Root | null = null;

let xPayInitCompleted = false;

export const initDocument = () => {
  if (isServer) {
    return;
  }
  createXPayInitIndicatorRoot();

  setupFonts();

  Promise.all([createXPayRoot(), createXPayTxStatusRoot()]).then((roots) => {
    for (const root of roots) {
      attachStyles(root);
    }

    xPayInitCompleted = true;
  });
};

export const waitForInitialization = async () => {
  if (!xPayInitCompleted) {
    displayInitIndicator(true);
    while (!xPayInitCompleted) {
      await new Promise((resolve) => setTimeout(resolve, 10));
    }
    displayInitIndicator(false);
  }
};

const attachStyles = async (root: ShadowRoot) => {
  const style = document.createElement("style");
  style.appendChild(document.createTextNode(CSS));
  root.appendChild(style);
};

/**
 * To let Web Components use custom fonts, we need to define them on the page's document.
 */
const setupFonts = () => {
  const SELECTOR_KEY = "xpay-fonts";

  if (document.querySelector(`style[data-name="${SELECTOR_KEY}"]`)) {
    return;
  }

  const style = document.createElement("style");
  style.dataset.name = SELECTOR_KEY;

  style.appendChild(document.createTextNode(fontDefinitions));
  document.head.appendChild(style);
};

const createXPayRoot = async () => {
  const xswapElement = document.createElement("div");
  xpayShadowRoot = xswapElement.attachShadow({
    mode: "open",
  });
  xswapElement.setAttribute("id", "xpay-root");
  document.body.appendChild(xswapElement);
  xpayRoot = createRoot(xpayShadowRoot);
  return xpayShadowRoot;
};

const createXPayTxStatusRoot = async () => {
  const txStatusElement = document.createElement("div");
  const shadow = txStatusElement.attachShadow({ mode: "open" });
  txStatusElement.setAttribute("id", "xpay-tx-status");
  document.body.appendChild(txStatusElement);
  xpayTxStatusRoot = createRoot(shadow);
  return shadow;
};

const createXPayInitIndicatorRoot = () => {
  const initIndicatorElement = document.createElement("div");
  initIndicatorElement.setAttribute("id", "xpay-init-indicator");
  document.body.appendChild(initIndicatorElement);
  xpayInitIndicatorRoot = createRoot(initIndicatorElement);
};

const displayInitIndicator = (display: boolean) => {
  if (isServer || !xpayInitIndicatorRoot) {
    return;
  }
  display
    ? xpayInitIndicatorRoot.render(<WaitingForInit />)
    : xpayInitIndicatorRoot.render(null);
};
