(() => {
  const DRAG_FREE_ENABLED_KEY = "dragFreeEnabled";
  const STYLE_ID = "__one_drag_free_style__";
  const BLOCKED_EVENTS = ["contextmenu", "selectstart", "dragstart", "copy", "cut"];
  const POINTER_EVENTS = ["mousedown", "mouseup", "mousemove", "pointerdown", "pointerup", "pointermove"];

  let enabled = false;

  chrome.storage.sync.get({ [DRAG_FREE_ENABLED_KEY]: false }, (settings) => {
    enabled = settings[DRAG_FREE_ENABLED_KEY] === true;
    syncStyle();
  });

  chrome.storage.onChanged.addListener((changes, areaName) => {
    if (areaName !== "sync" || !changes[DRAG_FREE_ENABLED_KEY]) {
      return;
    }

    enabled = changes[DRAG_FREE_ENABLED_KEY].newValue === true;
    syncStyle();
  });

  for (const type of BLOCKED_EVENTS) {
    window.addEventListener(type, allowBlockedUserAction, true);
    document.addEventListener(type, allowBlockedUserAction, true);
  }

  for (const type of POINTER_EVENTS) {
    window.addEventListener(type, allowPointerAction, true);
    document.addEventListener(type, allowPointerAction, true);
  }

  function allowBlockedUserAction(event) {
    if (!enabled || event.__oneDragFreeHandled) {
      return;
    }

    event.__oneDragFreeHandled = true;
    event.stopImmediatePropagation();
  }

  function allowPointerAction(event) {
    if (!enabled || event.__oneDragFreeHandled || shouldLeavePointerEventAlone(event)) {
      return;
    }

    event.__oneDragFreeHandled = true;
    event.stopImmediatePropagation();
  }

  function shouldLeavePointerEventAlone(event) {
    if (event.shiftKey || event.ctrlKey || event.metaKey || event.altKey || event.button === 1) {
      return true;
    }

    const target = event.target?.nodeType === Node.ELEMENT_NODE ? event.target : event.target?.parentElement;
    return Boolean(target?.closest?.([
      "a",
      "button",
      "input",
      "textarea",
      "select",
      "option",
      "label",
      "video",
      "audio",
      "[contenteditable='true']",
      "[role='button']",
      "[role='link']",
      "[role='textbox']",
      "[role='menuitem']"
    ].join(",")));
  }

  function syncStyle() {
    if (enabled) {
      ensureStyle();
      return;
    }

    document.getElementById(STYLE_ID)?.remove();
  }

  function ensureStyle() {
    if (document.getElementById(STYLE_ID)) {
      return;
    }

    const style = document.createElement("style");
    style.id = STYLE_ID;
    style.textContent = `
      html, body, body * {
        -webkit-user-select: text !important;
        user-select: text !important;
        -webkit-touch-callout: default !important;
      }
    `;
    appendStyle(style);
  }

  function appendStyle(style) {
    const root = document.documentElement || document.head || document.body;
    if (root) {
      root.appendChild(style);
      return;
    }

    window.setTimeout(() => appendStyle(style), 10);
  }
})();
