import { jsx } from 'react/jsx-runtime';
import { css } from '@emotion/css';
import { useRef, useState, useLayoutEffect } from 'react';
import { useMountedState } from 'react-use';
import { DashboardCursorSync, getDisplayProcessor, formattedValueToString, getFieldDisplayName, FALLBACK_COLOR, FieldType, arrayUtils } from '@grafana/data';
import { TooltipDisplayMode, SortOrder } from '@grafana/schema';
import { Portal } from '../../../components/Portal/Portal.mjs';
import { SeriesTable } from '../../../components/VizTooltip/SeriesTable.mjs';
import { VizTooltipContainer } from '../../../components/VizTooltip/VizTooltipContainer.mjs';
import { findMidPointYPosition } from '../../../components/uPlot/utils.mjs';
import { useTheme2, useStyles2 } from '../../../themes/ThemeContext.mjs';

"use strict";
const TOOLTIP_OFFSET = 10;
const TooltipPlugin = ({
  mode = TooltipDisplayMode.Single,
  sortOrder = SortOrder.None,
  sync,
  timeZone,
  config,
  renderTooltip,
  ...otherProps
}) => {
  var _a, _b, _c, _d, _e;
  const plotInstance = useRef();
  const theme = useTheme2();
  const [focusedSeriesIdx, setFocusedSeriesIdx] = useState(null);
  const [focusedPointIdx, setFocusedPointIdx] = useState(null);
  const [focusedPointIdxs, setFocusedPointIdxs] = useState([]);
  const [coords, setCoords] = useState(null);
  const [isActive, setIsActive] = useState(false);
  const isMounted = useMountedState();
  let parentWithFocus = null;
  const style = useStyles2(getStyles);
  useLayoutEffect(() => {
    let bbox = void 0;
    const plotEnter = () => {
      var _a2;
      if (!isMounted()) {
        return;
      }
      setIsActive(true);
      (_a2 = plotInstance.current) == null ? void 0 : _a2.root.classList.add("plot-active");
    };
    const plotLeave = () => {
      var _a2;
      if (!isMounted()) {
        return;
      }
      setCoords(null);
      setIsActive(false);
      (_a2 = plotInstance.current) == null ? void 0 : _a2.root.classList.remove("plot-active");
    };
    config.addHook("syncRect", (u, rect) => bbox = rect);
    config.addHook("init", (u) => {
      plotInstance.current = u;
      u.over.addEventListener("mouseenter", plotEnter);
      u.over.addEventListener("mouseleave", plotLeave);
      parentWithFocus = u.root.closest("[tabindex]");
      if (parentWithFocus) {
        parentWithFocus.addEventListener("focus", plotEnter);
        parentWithFocus.addEventListener("blur", plotLeave);
      }
      if (sync && sync() === DashboardCursorSync.Crosshair) {
        u.root.classList.add("shared-crosshair");
      }
    });
    config.addHook("setLegend", (u) => {
      if (!isMounted()) {
        return;
      }
      setFocusedPointIdx(u.legend.idx);
      setFocusedPointIdxs(u.legend.idxs.slice());
    });
    config.addHook("setCursor", (u) => {
      if (!bbox || !isMounted()) {
        return;
      }
      const { x, y } = positionTooltip(u, bbox);
      if (x !== void 0 && y !== void 0) {
        setCoords({ x, y });
      } else {
        setCoords(null);
      }
    });
    config.addHook("setSeries", (_, idx) => {
      if (!isMounted()) {
        return;
      }
      setFocusedSeriesIdx(idx);
    });
    return () => {
      setCoords(null);
      if (plotInstance.current) {
        plotInstance.current.over.removeEventListener("mouseleave", plotLeave);
        plotInstance.current.over.removeEventListener("mouseenter", plotEnter);
        if (parentWithFocus) {
          parentWithFocus.removeEventListener("focus", plotEnter);
          parentWithFocus.removeEventListener("blur", plotLeave);
        }
      }
    };
  }, [config, setCoords, setIsActive, setFocusedPointIdx, setFocusedPointIdxs]);
  if (focusedPointIdx === null || !isActive && sync && sync() === DashboardCursorSync.Crosshair) {
    return null;
  }
  let xField = otherProps.data.fields[0];
  if (!xField) {
    return null;
  }
  const xFieldFmt = xField.display || getDisplayProcessor({ field: xField, timeZone, theme });
  let tooltip = null;
  let xVal = xFieldFmt(xField.values[focusedPointIdx]).text;
  if (!renderTooltip) {
    if (mode === TooltipDisplayMode.Single && focusedSeriesIdx !== null) {
      const field = otherProps.data.fields[focusedSeriesIdx];
      if (!field) {
        return null;
      }
      const dataIdx = (_a = focusedPointIdxs == null ? void 0 : focusedPointIdxs[focusedSeriesIdx]) != null ? _a : focusedPointIdx;
      xVal = xFieldFmt(xField.values[dataIdx]).text;
      const fieldFmt = field.display || getDisplayProcessor({ field, timeZone, theme });
      const display = fieldFmt(field.values[dataIdx]);
      tooltip = /* @__PURE__ */ jsx(
        SeriesTable,
        {
          series: [
            {
              color: display.color || FALLBACK_COLOR,
              label: getFieldDisplayName(field, otherProps.data, otherProps.frames),
              value: display ? formattedValueToString(display) : null
            }
          ],
          timestamp: xVal
        }
      );
    }
    if (mode === TooltipDisplayMode.Multi) {
      let series = [];
      const frame = otherProps.data;
      const fields = frame.fields;
      const sortIdx = [];
      for (let i = 0; i < fields.length; i++) {
        const field = frame.fields[i];
        if (!field || field === xField || field.type === FieldType.time || field.type !== FieldType.number || ((_c = (_b = field.config.custom) == null ? void 0 : _b.hideFrom) == null ? void 0 : _c.tooltip) || ((_e = (_d = field.config.custom) == null ? void 0 : _d.hideFrom) == null ? void 0 : _e.viz)) {
          continue;
        }
        const v = otherProps.data.fields[i].values[focusedPointIdxs[i]];
        const display = field.display(v);
        sortIdx.push(v);
        series.push({
          color: display.color || FALLBACK_COLOR,
          label: getFieldDisplayName(field, frame, otherProps.frames),
          value: display ? formattedValueToString(display) : null,
          isActive: focusedSeriesIdx === i
        });
      }
      if (sortOrder !== SortOrder.None) {
        const sortRef = [...series];
        const sortFn = arrayUtils.sortValues(sortOrder);
        series.sort((a, b) => {
          const aIdx = sortRef.indexOf(a);
          const bIdx = sortRef.indexOf(b);
          return sortFn(sortIdx[aIdx], sortIdx[bIdx]);
        });
      }
      tooltip = /* @__PURE__ */ jsx(SeriesTable, { series, timestamp: xVal });
    }
  } else {
    tooltip = renderTooltip(otherProps.data, focusedSeriesIdx, focusedPointIdx);
  }
  return /* @__PURE__ */ jsx(Portal, { className: isActive ? style.tooltipWrapper : void 0, children: tooltip && coords && /* @__PURE__ */ jsx(VizTooltipContainer, { position: { x: coords.x, y: coords.y }, offset: { x: TOOLTIP_OFFSET, y: TOOLTIP_OFFSET }, children: tooltip }) });
};
function isCursorOutsideCanvas({ left, top }, canvas) {
  if (left === void 0 || top === void 0) {
    return false;
  }
  return left < 0 || left > canvas.width || top < 0 || top > canvas.height;
}
function positionTooltip(u, bbox) {
  let x, y;
  const cL = u.cursor.left || 0;
  const cT = u.cursor.top || 0;
  if (isCursorOutsideCanvas(u.cursor, bbox)) {
    const idx = u.posToIdx(cL);
    if (cT < 0 || cT > bbox.height) {
      let pos = findMidPointYPosition(u, idx);
      if (pos) {
        y = bbox.top + pos;
        if (cL >= 0 && cL <= bbox.width) {
          x = bbox.left + u.valToPos(u.data[0][u.posToIdx(cL)], u.series[0].scale);
        }
      }
    }
  } else {
    x = bbox.left + cL;
    y = bbox.top + cT;
  }
  return { x, y };
}
const getStyles = (theme) => ({
  tooltipWrapper: css({
    "z-index": theme.zIndex.portal + 1 + " !important"
  })
});

export { TooltipPlugin, positionTooltip };
//# sourceMappingURL=TooltipPlugin.mjs.map
