import { jsx, jsxs } from 'react/jsx-runtime';
import $ from 'jquery';
import { uniqBy } from 'lodash';
import * as React from 'react';
import { PureComponent } from 'react';
import { createDimension } from '@grafana/data';
import { TooltipDisplayMode } from '@grafana/schema';
import '../../components/VizTooltip/index.mjs';
import { GraphContextMenu } from './GraphContextMenu.mjs';
import { GraphTooltip } from './GraphTooltip/GraphTooltip.mjs';
import { graphTickFormatter, graphTimeFormat } from './utils.mjs';
import { VizTooltip } from '../../components/VizTooltip/VizTooltip.mjs';

"use strict";
class Graph extends PureComponent {
  constructor() {
    super(...arguments);
    this.state = {
      isTooltipVisible: false,
      isContextVisible: false
    };
    this.element = null;
    this.$element = null;
    this.onPlotSelected = (event, ranges) => {
      const { onHorizontalRegionSelected } = this.props;
      if (onHorizontalRegionSelected) {
        onHorizontalRegionSelected(ranges.xaxis.from, ranges.xaxis.to);
      }
    };
    this.onPlotHover = (event, pos, item) => {
      this.setState({
        isTooltipVisible: true,
        activeItem: item,
        pos
      });
    };
    this.onPlotClick = (event, contextPos, item) => {
      this.setState({
        isContextVisible: true,
        isTooltipVisible: false,
        contextItem: item,
        contextPos
      });
    };
    this.renderTooltip = () => {
      const { children, series, timeZone } = this.props;
      const { pos, activeItem, isTooltipVisible } = this.state;
      let tooltipElement;
      if (!isTooltipVisible || !pos || series.length === 0) {
        return null;
      }
      React.Children.forEach(children, (c) => {
        if (tooltipElement) {
          return;
        }
        const childType = c && c.type && (c.type.displayName || c.type.name);
        if (childType === VizTooltip.displayName) {
          tooltipElement = c;
        }
      });
      if (!tooltipElement) {
        return null;
      }
      const tooltipElementProps = tooltipElement.props;
      const tooltipMode = tooltipElementProps.mode || "single";
      if (!activeItem && tooltipMode === "single") {
        return null;
      }
      const tooltipContentRenderer = tooltipElementProps.tooltipComponent || GraphTooltip;
      const seriesIndex = activeItem ? activeItem.series.seriesIndex : 0;
      const rowIndex = activeItem ? activeItem.dataIndex : void 0;
      const activeDimensions = {
        // Described x-axis active item
        // When hovering over an item - let's take it's dataIndex, otherwise undefined
        // Tooltip itself needs to figure out correct datapoint display information based on pos passed to it
        xAxis: [seriesIndex, rowIndex],
        // Describes y-axis active item
        yAxis: activeItem ? [activeItem.series.seriesIndex, activeItem.dataIndex] : null
      };
      const tooltipContentProps = {
        dimensions: {
          // time/value dimension columns are index-aligned - see getGraphSeriesModel
          xAxis: createDimension(
            "xAxis",
            series.map((s) => s.timeField)
          ),
          yAxis: createDimension(
            "yAxis",
            series.map((s) => s.valueField)
          )
        },
        activeDimensions,
        pos,
        mode: tooltipElementProps.mode || TooltipDisplayMode.Single,
        timeZone
      };
      const tooltipContent = React.createElement(tooltipContentRenderer, { ...tooltipContentProps });
      return React.cloneElement(tooltipElement, {
        content: tooltipContent,
        position: { x: pos.pageX, y: pos.pageY },
        offset: { x: 10, y: 10 }
      });
    };
    this.renderContextMenu = () => {
      const { series } = this.props;
      const { contextPos, contextItem, isContextVisible } = this.state;
      if (!isContextVisible || !contextPos || !contextItem || series.length === 0) {
        return null;
      }
      const seriesIndex = contextItem ? contextItem.series.seriesIndex : 0;
      const rowIndex = contextItem ? contextItem.dataIndex : void 0;
      const contextDimensions = {
        // Described x-axis context item
        xAxis: [seriesIndex, rowIndex],
        // Describes y-axis context item
        yAxis: contextItem ? [contextItem.series.seriesIndex, contextItem.dataIndex] : null
      };
      const dimensions = {
        // time/value dimension columns are index-aligned - see getGraphSeriesModel
        xAxis: createDimension(
          "xAxis",
          series.map((s) => s.timeField)
        ),
        yAxis: createDimension(
          "yAxis",
          series.map((s) => s.valueField)
        )
      };
      const closeContext = () => this.setState({ isContextVisible: false });
      const getContextMenuSource = () => {
        return {
          datapoint: contextItem.datapoint,
          dataIndex: contextItem.dataIndex,
          series: contextItem.series,
          seriesIndex: contextItem.series.seriesIndex,
          pageX: contextPos.pageX,
          pageY: contextPos.pageY
        };
      };
      const contextContentProps = {
        x: contextPos.pageX,
        y: contextPos.pageY,
        onClose: closeContext,
        getContextMenuSource,
        timeZone: this.props.timeZone,
        dimensions,
        contextDimensions
      };
      return /* @__PURE__ */ jsx(GraphContextMenu, { ...contextContentProps });
    };
    this.getBarWidth = () => {
      const { series } = this.props;
      return Math.min(...series.map((s) => s.timeStep));
    };
  }
  componentDidUpdate(prevProps, prevState) {
    if (prevProps !== this.props) {
      this.draw();
    }
  }
  componentDidMount() {
    this.draw();
    if (this.element) {
      this.$element = $(this.element);
      this.$element.bind("plotselected", this.onPlotSelected);
      this.$element.bind("plothover", this.onPlotHover);
      this.$element.bind("plotclick", this.onPlotClick);
    }
  }
  componentWillUnmount() {
    if (this.$element) {
      this.$element.unbind("plotselected", this.onPlotSelected);
    }
  }
  getYAxes(series) {
    if (series.length === 0) {
      return [{ show: true, min: -1, max: 1 }];
    }
    return uniqBy(
      series.map((s) => {
        const index = s.yAxis ? s.yAxis.index : 1;
        const min = s.yAxis && s.yAxis.min && !isNaN(s.yAxis.min) ? s.yAxis.min : null;
        const tickDecimals = s.yAxis && s.yAxis.tickDecimals && !isNaN(s.yAxis.tickDecimals) ? s.yAxis.tickDecimals : null;
        return {
          show: true,
          index,
          position: index === 1 ? "left" : "right",
          min,
          tickDecimals
        };
      }),
      (yAxisConfig) => yAxisConfig.index
    );
  }
  draw() {
    if (this.element === null) {
      return;
    }
    const {
      width,
      series,
      timeRange,
      showLines,
      showBars,
      showPoints,
      isStacked,
      lineWidth,
      timeZone,
      onHorizontalRegionSelected
    } = this.props;
    if (!width) {
      return;
    }
    const ticks = width / 100;
    const min = timeRange.from.valueOf();
    const max = timeRange.to.valueOf();
    const yaxes = this.getYAxes(series);
    const flotOptions = {
      legend: {
        show: false
      },
      series: {
        stack: isStacked,
        lines: {
          show: showLines,
          lineWidth,
          zero: false
        },
        points: {
          show: showPoints,
          fill: 1,
          fillColor: false,
          radius: 2
        },
        bars: {
          show: showBars,
          fill: 1,
          // Dividig the width by 1.5 to make the bars not touch each other
          barWidth: showBars ? this.getBarWidth() / 1.5 : 1,
          zero: false,
          lineWidth
        },
        shadowSize: 0
      },
      xaxis: {
        timezone: timeZone,
        show: true,
        mode: "time",
        min,
        max,
        label: "Datetime",
        ticks,
        timeformat: graphTimeFormat(ticks, min, max),
        tickFormatter: graphTickFormatter
      },
      yaxes,
      grid: {
        minBorderMargin: 0,
        markings: [],
        backgroundColor: null,
        borderWidth: 0,
        hoverable: true,
        clickable: true,
        color: "#a1a1a1",
        margin: { left: 0, right: 0 },
        labelMarginX: 0,
        mouseActiveRadius: 30
      },
      selection: {
        mode: onHorizontalRegionSelected ? "x" : null,
        color: "#666"
      },
      crosshair: {
        mode: "x"
      }
    };
    try {
      $.plot(
        this.element,
        series.filter((s) => s.isVisible),
        flotOptions
      );
    } catch (err) {
      console.error("Graph rendering error", err, flotOptions, series);
      throw new Error("Error rendering panel");
    }
  }
  render() {
    const { ariaLabel, height, width, series } = this.props;
    const noDataToBeDisplayed = series.length === 0;
    const tooltip = this.renderTooltip();
    const context = this.renderContextMenu();
    return /* @__PURE__ */ jsxs("div", { className: "graph-panel", "aria-label": ariaLabel, children: [
      /* @__PURE__ */ jsx(
        "div",
        {
          className: "graph-panel__chart",
          ref: (e) => this.element = e,
          style: { height, width },
          onMouseLeave: () => {
            this.setState({ isTooltipVisible: false });
          }
        }
      ),
      noDataToBeDisplayed && /* @__PURE__ */ jsx("div", { className: "datapoints-warning", children: "No data" }),
      tooltip,
      context
    ] });
  }
}
Graph.defaultProps = {
  showLines: true,
  showPoints: false,
  showBars: false,
  isStacked: false,
  lineWidth: 1
};

export { Graph, Graph as default };
//# sourceMappingURL=Graph.mjs.map
