import { debounce } from "./dom-utils.js";
import { emitEvent, listenTo } from "./events.js";
import { registerLoadCallback } from "./main.js";
import { makeAtlasImage } from "./atlas.js";
import { DevError } from "./errors.js";
import { getCellTooltip } from "./planner.js";

const tooltips = {};
let tooltipsCounter = 0;
let lastCoordinates = null;
let suppressTooltips = false;
let activeTooltipTarget = null;

registerLoadCallback(() => {
  document.querySelectorAll("[data-retain-tooltip-hover]").forEach(elem =>
      elem.addEventListener("mousemove", retainTooltipHover));
  window.addEventListener("mousemove", () => {
    if (lastCoordinates !== null) {
      emitEvent("tooltips:hide");
    }
    lastCoordinates = null;
  });
  window.addEventListener("mousemove", debounce(e => {
    lastCoordinates = { x: e.pageX, y: e.pageY };
    emitEvent("tooltips:show");
  }, 500));
  window.addEventListener("wheel", () => {
    if (lastCoordinates !== null) {
      setTimeout(() => emitEvent("tooltips:show"), 200);
    }
  });

  listenTo("tooltips:show", showTooltip);
  listenTo("tooltips:hide", hideTooltip);

  listenTo("dev:suppress-tooltips", () => {
    suppressTooltips = !suppressTooltips;
    console.log("suppressing tooltips", suppressTooltips);
  });
});

export function retainTooltipHover(e) {
  if (lastCoordinates !== null) {
    e.stopPropagation();
    lastCoordinates = { x: e.pageX, y: e.pageY };
    emitEvent("tooltips:show");
  }
}

export function createTooltip(data) {
  const id = tooltipsCounter;
  tooltips[id] = data;
  tooltipsCounter++;
  return id;
}

export function getTooltip(id) {
  if (typeof id === "object") {
    // assume DOM element
    if (id.dataset && id.dataset.tooltip) {
      return getTooltip(id.dataset.tooltip);
    }
    return null;
  }
  return tooltips[id];
}

export function deleteTooltip(id) {
  delete tooltips[id];
}

export function setTooltip(element, data) {
  if (data.length === 0) return;

  if (element.dataset.tooltip) {
    tooltips[Number(element.dataset.tooltip)] = data;
    return;
  }
  element.dataset.tooltip = createTooltip(data).toString(10);
}

export function positionAsTooltip(mainElement, tooltipElement, { horizontal = "left", vertical = "bottom" } = {}) {
  const targetRect = mainElement.getBoundingClientRect();
  const domRect = tooltipElement.getBoundingClientRect();
  const windowWidth = window.innerWidth, windowHeight = window.innerHeight;
  tooltipElement.style.left = `${Math.min(targetRect[horizontal], windowWidth - domRect.width)}px`;
  tooltipElement.style.top = `${Math.min(targetRect[vertical], windowHeight - domRect.height)}px`;
}

function showTooltip() {
  if (suppressTooltips) return;
  if (!lastCoordinates) return;

  let target = document.elementFromPoint(lastCoordinates.x, lastCoordinates.y);
  while (target && !target.dataset.tooltip) {
    target = target.parentElement;
  }
  if (!target) return;

  if (!target.isSameNode(activeTooltipTarget)) hideTooltip();
  else return;

  const dom = target.dataset.tooltip === "auto"
      ? createAutoTooltipDom(target)
      : createTooltipDom(tooltips[target.dataset.tooltip]);
  if (!dom) return;

  const targetRect = target.getBoundingClientRect();
  dom.style.left = `${targetRect.left}px`;
  dom.style.top = `${targetRect.bottom}px`;

  target.appendChild(dom);
  positionAsTooltip(target, dom);

  activeTooltipTarget = target;
}
function hideTooltip() {
  if (suppressTooltips) return;
  if (!activeTooltipTarget) return;

  const tooltip = activeTooltipTarget.querySelector(".tooltip");
  if (!tooltip) return;

  activeTooltipTarget.removeChild(tooltip);
  activeTooltipTarget = null;
}

function createTooltipDom(data) {
  if (!Array.isArray(data)) {
    throw new DevError(`tooltip is not an array: ${data}`);
  }
  if (data.length === 0) {
    return null;
  }
  const div = document.createElement("div");
  div.classList.add("tooltip");
  for (const row of data) {
    const rowElem = document.createElement("div");

    if (typeof row === "string") {
      rowElem.innerText = row;
    } else {
      if (!row.type) {
        throw row;
      }
      // TODO: support richer tooltips
      switch (row.type) {
        case "italics":
          rowElem.innerText = row.text;
          rowElem.classList.add("italics");
          break;

        case "item":
          if (row.prefix) {
            rowElem.appendChild(document.createTextNode(row.prefix));
          }
          rowElem.appendChild(makeAtlasImage(row.atlasIndex));
          rowElem.appendChild(document.createTextNode(row.name));
          rowElem.classList.add("tooltip--item");
          break;

        case "meta":
          break;

        default:
          console.warn("unknown tooltip type", row);
          break;
      }
    }

    div.appendChild(rowElem);
  }
  return div;
}

function createAutoTooltipDom(element) {
  if (element.dataset.x && element.dataset.tile) {
    return createTooltipDom([...getCellTooltip(element)]);
  }
  throw new DevError(`unknown element for auto tooltip: ${element}`);
}

export function tooltipDataToPlain(data) {
  if (!Array.isArray(data)) {
    console.warn("tooltip data is not an array: %o", data);
    return [];
  }

  return data.flatMap(row => {
    if (typeof row === "string") return row;
    if (!row.type) return [];
    if (row.text) return row.text;
    if (row.type === "item") return row.name;
    if (row.type === "meta") return [];
    return [];
  })
}
