import { cx, css } from '@emotion/css';
import React__default, { useRef, useReducer, useContext, useEffect, useLayoutEffect } from 'react';
import { createPortal } from 'react-dom';
import '@grafana/data';
import { useStyles2 } from '../../../themes/ThemeContext.js';
import 'micro-memoize';
import '@emotion/react';
import 'tinycolor2';
import '../../../utils/skeleton.js';
import { LayoutItemContext } from '../../Layout/LayoutItemContext.js';
import { CloseButton } from './CloseButton.js';

var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
  for (var prop in b || (b = {}))
    if (__hasOwnProp.call(b, prop))
      __defNormalProp(a, prop, b[prop]);
  if (__getOwnPropSymbols)
    for (var prop of __getOwnPropSymbols(b)) {
      if (__propIsEnum.call(b, prop))
        __defNormalProp(a, prop, b[prop]);
    }
  return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
const DEFAULT_TOOLTIP_WIDTH = void 0;
const DEFAULT_TOOLTIP_HEIGHT = void 0;
const TOOLTIP_OFFSET = 10;
function mergeState(prevState, nextState) {
  return __spreadProps(__spreadValues(__spreadValues({}, prevState), nextState), {
    style: __spreadValues(__spreadValues({}, prevState.style), nextState.style)
  });
}
const INITIAL_STATE = {
  style: { transform: "", pointerEvents: "none" },
  isHovering: false,
  isPinned: false,
  contents: null,
  plot: null,
  dismiss: () => {
  }
};
const MIN_ZOOM_DIST = 5;
const maybeZoomAction = (e) => e != null && !e.ctrlKey && !e.metaKey;
const TooltipPlugin2 = ({
  config,
  hoverMode,
  render,
  clientZoom = false,
  queryZoom,
  maxWidth,
  maxHeight
}) => {
  const domRef = useRef(null);
  const [{ plot, isHovering, isPinned, contents, style, dismiss }, setState] = useReducer(mergeState, INITIAL_STATE);
  const { boostZIndex } = useContext(LayoutItemContext);
  useEffect(() => isPinned ? boostZIndex() : void 0, [isPinned]);
  const sizeRef = useRef();
  maxWidth = isPinned ? DEFAULT_TOOLTIP_WIDTH : maxWidth != null ? maxWidth : DEFAULT_TOOLTIP_WIDTH;
  maxHeight != null ? maxHeight : maxHeight = DEFAULT_TOOLTIP_HEIGHT;
  const styles = useStyles2(getStyles, maxWidth, maxHeight);
  const renderRef = useRef(render);
  renderRef.current = render;
  useLayoutEffect(() => {
    sizeRef.current = {
      width: 0,
      height: 0,
      observer: new ResizeObserver((entries) => {
        var _a;
        let size = sizeRef.current;
        for (const entry of entries) {
          if (((_a = entry.borderBoxSize) == null ? void 0 : _a.length) > 0) {
            size.width = entry.borderBoxSize[0].inlineSize;
            size.height = entry.borderBoxSize[0].blockSize;
          } else {
            size.width = entry.contentRect.width;
            size.height = entry.contentRect.height;
          }
        }
      })
    };
    let yZoomed = false;
    let yDrag = false;
    let _plot = plot;
    let _isHovering = isHovering;
    let _someSeriesIdx = false;
    let _isPinned = isPinned;
    let _style = style;
    const updateHovering = () => {
      _isHovering = closestSeriesIdx != null || hoverMode === 1 /* xAll */ && _someSeriesIdx;
    };
    let offsetX = 0;
    let offsetY = 0;
    let containRect = {
      lft: 0,
      top: 0,
      rgt: screen.width,
      btm: screen.height
    };
    let selectedRange = null;
    let seriesIdxs = plot == null ? void 0 : plot.cursor.idxs.slice();
    let closestSeriesIdx = null;
    let viaSync = false;
    let pendingRender = false;
    let pendingPinned = false;
    const scheduleRender = (setPinned = false) => {
      if (!pendingRender) {
        if (!_isHovering) {
          setTimeout(_render, 100);
        } else {
          queueMicrotask(_render);
        }
        pendingRender = true;
      }
      if (setPinned) {
        pendingPinned = true;
      }
    };
    const downEventOutside = (e) => {
      if (!domRef.current.contains(e.target)) {
        dismiss2();
      }
    };
    const _render = () => {
      pendingRender = false;
      if (pendingPinned) {
        _style = { pointerEvents: _isPinned ? "all" : "none" };
        _plot.cursor._lock = _isPinned;
        if (_isPinned) {
          document.addEventListener("mousedown", downEventOutside, true);
          document.addEventListener("keydown", downEventOutside, true);
        } else {
          document.removeEventListener("mousedown", downEventOutside, true);
          document.removeEventListener("keydown", downEventOutside, true);
        }
        pendingPinned = false;
      }
      let state = {
        style: _style,
        isPinned: _isPinned,
        isHovering: _isHovering,
        contents: _isHovering || selectedRange != null ? renderRef.current(_plot, seriesIdxs, closestSeriesIdx, _isPinned, dismiss2, selectedRange, viaSync) : null,
        dismiss: dismiss2
      };
      setState(state);
      selectedRange = null;
      viaSync = false;
    };
    const dismiss2 = () => {
      let prevIsPinned = _isPinned;
      _isPinned = false;
      _isHovering = false;
      _plot.setCursor({ left: -10, top: -10 });
      scheduleRender(prevIsPinned);
    };
    config.addHook("init", (u) => {
      setState({ plot: _plot = u });
      if (clientZoom) {
        u.over.addEventListener(
          "mousedown",
          (e) => {
            if (!maybeZoomAction(e)) {
              return;
            }
            if (e.button === 0 && e.shiftKey) {
              yDrag = true;
              u.cursor.drag.x = false;
              u.cursor.drag.y = true;
              let onUp = (e2) => {
                u.cursor.drag.x = true;
                u.cursor.drag.y = false;
                document.removeEventListener("mouseup", onUp, true);
              };
              document.addEventListener("mouseup", onUp, true);
            }
          },
          true
        );
      }
      u.over.addEventListener("click", (e) => {
        if (e.target === u.over) {
          if (e.ctrlKey || e.metaKey) {
            let xVal = u.posToVal(u.cursor.left, "x");
            selectedRange = {
              from: xVal,
              to: xVal
            };
            scheduleRender(false);
          } else if (_isHovering && closestSeriesIdx != null && !_isPinned) {
            _isPinned = true;
            scheduleRender(true);
          }
        }
      });
      const haltAncestorId = "pageContent";
      const scrollbarWidth = 16;
      u.over.addEventListener(
        "mouseenter",
        () => {
          let htmlEl = document.documentElement;
          let winWid = htmlEl.clientWidth - scrollbarWidth;
          let winHgt = htmlEl.clientHeight - scrollbarWidth;
          let lft = 0, top = 0, rgt = winWid, btm = winHgt;
          let par = u.root;
          while (par != null && par.id !== haltAncestorId) {
            let style2 = getComputedStyle(par);
            let overflowX = style2.getPropertyValue("overflow-x");
            let overflowY = style2.getPropertyValue("overflow-y");
            if (overflowX !== "visible" || overflowY !== "visible") {
              let rect = par.getBoundingClientRect();
              lft = Math.max(rect.x, lft);
              top = Math.max(rect.y, top);
              rgt = Math.min(lft + rect.width, rgt);
              btm = Math.min(top + rect.height, btm);
              break;
            }
            par = par.parentElement;
          }
          containRect.lft = lft;
          containRect.top = top;
          containRect.rgt = rgt;
          containRect.btm = btm;
        },
        { capture: true }
      );
    });
    config.addHook("setSelect", (u) => {
      let e = u.cursor.event;
      if (e != null && (clientZoom || queryZoom != null)) {
        if (maybeZoomAction(e)) {
          if (clientZoom && yDrag) {
            if (u.select.height >= MIN_ZOOM_DIST) {
              for (let key in u.scales) {
                if (key !== "x") {
                  const maxY = u.posToVal(u.select.top, key);
                  const minY = u.posToVal(u.select.top + u.select.height, key);
                  u.setScale(key, { min: minY, max: maxY });
                }
              }
              yZoomed = true;
            }
            yDrag = false;
          } else if (queryZoom != null) {
            if (u.select.width >= MIN_ZOOM_DIST) {
              const minX = u.posToVal(u.select.left, "x");
              const maxX = u.posToVal(u.select.left + u.select.width, "x");
              queryZoom({ from: minX, to: maxX });
              yZoomed = false;
            }
          }
        } else {
          selectedRange = {
            from: u.posToVal(u.select.left, "x"),
            to: u.posToVal(u.select.left + u.select.width, "x")
          };
          scheduleRender(true);
        }
      }
      u.setSelect({ left: 0, width: 0, top: 0, height: 0 }, false);
    });
    if (clientZoom || queryZoom != null) {
      config.setCursor({
        bind: {
          dblclick: (u) => () => {
            if (!maybeZoomAction(u.cursor.event)) {
              return null;
            }
            if (clientZoom && yZoomed) {
              for (let key in u.scales) {
                if (key !== "x") {
                  u.setScale(key, { min: null, max: null });
                }
              }
              yZoomed = false;
            } else if (queryZoom != null) {
              let xScale = u.scales.x;
              const frTs = xScale.min;
              const toTs = xScale.max;
              const pad = (toTs - frTs) / 2;
              queryZoom({ from: frTs - pad, to: toTs + pad });
            }
            return null;
          }
        }
      });
    }
    config.addHook("setData", (u) => {
      yZoomed = false;
      yDrag = false;
    });
    config.addHook("setSeries", (u, seriesIdx) => {
      closestSeriesIdx = seriesIdx;
      updateHovering();
      scheduleRender();
    });
    config.addHook("setLegend", (u) => {
      seriesIdxs = _plot == null ? void 0 : _plot.cursor.idxs.slice();
      _someSeriesIdx = seriesIdxs.some((v, i) => i > 0 && v != null);
      updateHovering();
      scheduleRender();
    });
    config.addHook("setCursor", (u) => {
      let { left = -10, top = -10, event } = u.cursor;
      if (left >= 0 || top >= 0) {
        viaSync = event == null;
        let transform = "";
        if (viaSync) {
          transform = `translateX(${left}px) translateY(${u.rect.height / 2}px) translateY(-50%)`;
        } else {
          let { width, height } = sizeRef.current;
          width += TOOLTIP_OFFSET;
          height += TOOLTIP_OFFSET;
          let clientX = u.rect.left + left;
          let clientY = u.rect.top + top;
          if (offsetY !== 0) {
            if (clientY + height < containRect.btm || clientY - height < 0) {
              offsetY = 0;
            } else if (offsetY !== -height) {
              offsetY = -height;
            }
          } else {
            if (clientY + height > containRect.btm && clientY - height >= 0) {
              offsetY = -height;
            }
          }
          if (offsetX !== 0) {
            if (clientX + width < containRect.rgt || clientX - width < 0) {
              offsetX = 0;
            } else if (offsetX !== -width) {
              offsetX = -width;
            }
          } else {
            if (clientX + width > containRect.rgt && clientX - width >= 0) {
              offsetX = -width;
            }
          }
          const shiftX = left + (offsetX === 0 ? TOOLTIP_OFFSET : -TOOLTIP_OFFSET);
          const shiftY = top + (offsetY === 0 ? TOOLTIP_OFFSET : -TOOLTIP_OFFSET);
          const reflectX = offsetX === 0 ? "" : "translateX(-100%)";
          const reflectY = offsetY === 0 ? "" : "translateY(-100%)";
          transform = `translateX(${shiftX}px) ${reflectX} translateY(${shiftY}px) ${reflectY}`;
        }
        if (_isHovering) {
          if (domRef.current != null) {
            domRef.current.style.transform = transform;
          } else {
            _style.transform = transform;
            scheduleRender();
          }
        }
      }
    });
  }, [config]);
  useLayoutEffect(() => {
    const size = sizeRef.current;
    if (domRef.current != null) {
      size.observer.observe(domRef.current);
    }
  }, [domRef.current]);
  if (plot && isHovering) {
    return createPortal(
      /* @__PURE__ */ React__default.createElement("div", { className: cx(styles.tooltipWrapper, isPinned && styles.pinned), style, ref: domRef }, isPinned && /* @__PURE__ */ React__default.createElement(CloseButton, { onClick: dismiss }), contents),
      plot.over
    );
  }
  return null;
};
const getStyles = (theme, maxWidth, maxHeight) => ({
  tooltipWrapper: css({
    top: 0,
    left: 0,
    zIndex: theme.zIndex.tooltip,
    whiteSpace: "pre",
    borderRadius: theme.shape.radius.default,
    position: "absolute",
    background: theme.colors.background.primary,
    border: `1px solid ${theme.colors.border.weak}`,
    boxShadow: theme.shadows.z2,
    userSelect: "text",
    maxWidth: maxWidth != null ? maxWidth : "none",
    maxHeight: maxHeight != null ? maxHeight : "none",
    overflowY: "auto"
  }),
  pinned: css({
    boxShadow: theme.shadows.z3
  })
});

export { DEFAULT_TOOLTIP_HEIGHT, DEFAULT_TOOLTIP_WIDTH, TOOLTIP_OFFSET, TooltipPlugin2 };
//# sourceMappingURL=TooltipPlugin2.js.map
