import { merge } from 'lodash';
import uPlot from 'uplot';
import { DefaultTimeZone, getTimeZoneInfo } from '@grafana/data';
import { AxisPlacement } from '@grafana/schema';
import { pluginLog, DEFAULT_PLOT_CONFIG, getStackingBands } from '../utils.mjs';
import { UPlotAxisBuilder } from './UPlotAxisBuilder.mjs';
import { UPlotScaleBuilder } from './UPlotScaleBuilder.mjs';
import { UPlotSeriesBuilder } from './UPlotSeriesBuilder.mjs';
import { getThresholdsDrawHook } from './UPlotThresholds.mjs';

"use strict";
const cursorDefaults = {
  // prevent client-side zoom from triggering at the end of a selection
  drag: { setScale: false },
  points: {
    /*@ts-ignore*/
    size: (u, seriesIdx) => u.series[seriesIdx].points.size * 2,
    /*@ts-ignore*/
    width: (u, seriesIdx, size) => size / 4
  },
  focus: {
    prox: 30
  }
};
class UPlotConfigBuilder {
  constructor(timeZone = DefaultTimeZone) {
    this.uid = Math.random().toString(36).slice(2);
    this.series = [];
    this.axes = {};
    this.scales = [];
    this.bands = [];
    this.stackingGroups = [];
    this.hasLeftAxis = false;
    this.hooks = {};
    this.tz = void 0;
    this.mode = 1;
    this.frames = void 0;
    // to prevent more than one threshold per scale
    this.thresholds = {};
    this.padding = void 0;
    this.prepData = void 0;
    // Exposed to let the container know the primary scale keys
    this.scaleKeys = ["", ""];
    this.tzDate = (ts) => {
      let date = new Date(ts);
      return this.tz ? uPlot.tzDate(date, this.tz) : date;
    };
    var _a;
    this.tz = (_a = getTimeZoneInfo(timeZone, Date.now())) == null ? void 0 : _a.ianaName;
  }
  addHook(type, hook) {
    pluginLog("UPlotConfigBuilder", false, "addHook", type);
    if (!this.hooks[type]) {
      this.hooks[type] = [];
    }
    this.hooks[type].push(hook);
  }
  addThresholds(options) {
    if (!this.thresholds[options.scaleKey]) {
      this.thresholds[options.scaleKey] = options;
      this.addHook("drawClear", getThresholdsDrawHook(options));
    }
  }
  addAxis(props) {
    var _a, _b, _c;
    props.placement = (_a = props.placement) != null ? _a : AxisPlacement.Auto;
    props.grid = (_b = props.grid) != null ? _b : {};
    let scaleKey = props.scaleKey;
    if (scaleKey === "x") {
      scaleKey += (_c = props.timeZone) != null ? _c : "";
    }
    if (this.axes[scaleKey]) {
      this.axes[scaleKey].merge(props);
      return;
    }
    if (props.placement === AxisPlacement.Auto) {
      props.placement = this.hasLeftAxis ? AxisPlacement.Right : AxisPlacement.Left;
    }
    if (props.placement === AxisPlacement.Left) {
      this.hasLeftAxis = true;
    }
    if (props.placement === AxisPlacement.Hidden) {
      props.grid.show = false;
      props.size = 0;
    }
    this.axes[scaleKey] = new UPlotAxisBuilder(props);
  }
  getAxisPlacement(scaleKey) {
    var _a;
    const axis = this.axes[scaleKey];
    return (_a = axis == null ? void 0 : axis.props.placement) != null ? _a : AxisPlacement.Left;
  }
  setCursor(cursor) {
    this.cursor = merge({}, this.cursor, cursor);
  }
  setMode(mode) {
    this.mode = mode;
  }
  setSelect(select) {
    this.select = select;
  }
  addSeries(props) {
    this.series.push(new UPlotSeriesBuilder(props));
  }
  getSeries() {
    return this.series;
  }
  /** Add or update the scale with the scale key */
  addScale(props) {
    const current = this.scales.find((v) => v.props.scaleKey === props.scaleKey);
    if (current) {
      current.merge(props);
      return;
    }
    this.scales.push(new UPlotScaleBuilder(props));
  }
  addBand(band) {
    this.bands.push(band);
  }
  setStackingGroups(groups) {
    this.stackingGroups = groups;
  }
  getStackingGroups() {
    return this.stackingGroups;
  }
  setPrepData(prepData) {
    this.prepData = (frames) => {
      this.frames = frames;
      return prepData(frames, this.getStackingGroups());
    };
  }
  setPadding(padding) {
    this.padding = padding;
  }
  getConfig() {
    if (this.cachedConfig) {
      return this.cachedConfig;
    }
    const config = {
      ...DEFAULT_PLOT_CONFIG,
      mode: this.mode,
      series: [
        this.mode === 2 ? null : {
          value: () => ""
        }
      ]
    };
    config.axes = this.ensureNonOverlappingAxes(Object.values(this.axes)).map((a) => a.getConfig());
    config.series = [...config.series, ...this.series.map((s) => s.getConfig())];
    config.scales = this.scales.reduce((acc, s) => {
      return { ...acc, ...s.getConfig() };
    }, {});
    config.hooks = this.hooks;
    config.select = this.select;
    const pointColorFn = (alphaHex = "") => (u, seriesIdx) => {
      let s = u.series[seriesIdx].points._stroke;
      if (typeof s !== "string") {
        let field = this.frames[0].fields[seriesIdx];
        s = field.display(field.values[u.cursor.idxs[seriesIdx]]).color;
      }
      return s + alphaHex;
    };
    config.cursor = merge(
      {},
      cursorDefaults,
      {
        points: {
          stroke: pointColorFn("80"),
          fill: pointColorFn()
        }
      },
      this.cursor
    );
    config.tzDate = this.tzDate;
    if (Array.isArray(this.padding)) {
      config.padding = this.padding;
    }
    this.stackingGroups.forEach((group) => {
      getStackingBands(group).forEach((band) => {
        this.addBand(band);
      });
    });
    if (this.bands.length) {
      config.bands = this.bands;
    }
    this.cachedConfig = config;
    return config;
  }
  ensureNonOverlappingAxes(axes) {
    const xAxis = axes.find((a) => a.props.scaleKey === "x");
    const axesWithoutGridSet = axes.filter((a) => {
      var _a;
      return ((_a = a.props.grid) == null ? void 0 : _a.show) === void 0;
    });
    const firstValueAxisIdx = axesWithoutGridSet.findIndex(
      (a) => a.props.placement === AxisPlacement.Left || a.props.placement === AxisPlacement.Right || a.props.placement === AxisPlacement.Bottom && a !== xAxis
    );
    for (let i = 0; i < axesWithoutGridSet.length; i++) {
      if (axesWithoutGridSet[i] === xAxis || i === firstValueAxisIdx) {
        axesWithoutGridSet[i].props.grid.show = true;
      } else {
        axesWithoutGridSet[i].props.grid.show = false;
      }
    }
    return axes;
  }
}

export { UPlotConfigBuilder };
//# sourceMappingURL=UPlotConfigBuilder.mjs.map
