import "../LineChart.css";
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
import React__default, { useRef, useMemo } from "react";
import { VirtuosoGrid } from "react-virtuoso";
import { glasbeyColor, getTimeTickValues } from "./internal/functions.js";
import ScaleSelect from "./internal/ScaleSelect.js";
import { XAxisDomain, Scale } from "./internal/types.js";
import UPlotChart from "./internal/UPlot/UPlotChart.js";
import { closestPointPlugin } from "./internal/UPlot/UPlotChart/closestPointPlugin.js";
import { tooltipsPlugin } from "./internal/UPlot/UPlotChart/tooltipsPlugin.js";
import { SyncProvider } from "./LineChart/SyncProvider.js";
import XAxisFilter from "./LineChart/XAxisFilter.js";
import Message from "./Message.js";
import { Row } from "./Row.js";
import Spinner from "./Spinner.js";
import Surface from "./Surface.js";
import { useTheme } from "./Theme/UI.js";
import "./Theme/themeUtils.js";
import "./Theme/themes.js";
import { Loadable } from "./utils/loadable.js";
const gridBase = "LineChart_gridBase_7f6d0";
const filterContainer = "LineChart_filterContainer_7f6d0";
const gridContainer = "LineChart_gridContainer_7f6d0";
const gridItem = "LineChart_gridItem_7f6d0";
const chartTitle = "LineChart_chartTitle_7f6d0";
const css = {
  gridBase,
  filterContainer,
  gridContainer,
  gridItem,
  chartTitle
};
const TRAINING_SERIES_COLOR = "#009BDE";
const VALIDATION_SERIES_COLOR = "#F77B21";
const getScientificNotationTickValues = (_self, rawValues) => {
  const useNotation = !!rawValues.find(
    (val) => val > 9999 || val < -9999 || 0 < val && val < 1e-4 || -1e-4 < val && val < 0
  );
  return useNotation ? rawValues.map((val) => val ? val.toExponential(2) : val) : rawValues.map((val) => val ? Number(val.toFixed(2)) : val);
};
const LineChart = ({
  focusedSeries,
  handleError,
  height = 350,
  optionKey,
  onPointClick,
  onPointFocus,
  scale = Scale.Linear,
  plugins: propPlugins,
  series: propSeries,
  showLegend = false,
  title,
  xAxis = XAxisDomain.Batches,
  xLabel,
  xRange,
  yLabel,
  yTickValues = getScientificNotationTickValues
}) => {
  const series = Loadable.ensureLoadable(propSeries).getOrElse([]);
  const isLoading = Loadable.isLoadable(propSeries) && Loadable.isNotLoaded(propSeries);
  const hasPopulatedSeries = useMemo(
    () => !!series.find((serie) => {
      var _a;
      return (_a = serie.data[xAxis]) == null ? void 0 : _a.length;
    }),
    [series, xAxis]
  );
  const seriesColors = useMemo(
    () => series.map((s, i) => s.color ?? glasbeyColor(i)),
    [series]
  );
  const chartData = useMemo(() => {
    var _a, _b;
    const xSet = /* @__PURE__ */ new Set();
    const yValues = {};
    const xMin = (_a = xRange == null ? void 0 : xRange[xAxis]) == null ? void 0 : _a[0];
    const xMax = (_b = xRange == null ? void 0 : xRange[xAxis]) == null ? void 0 : _b[1];
    if (xMin !== void 0 && xMax !== void 0) {
      xSet.add(xMin);
      xSet.add(xMax);
    }
    series.forEach((serie, serieIndex) => {
      yValues[serieIndex] = {};
      (serie.data[xAxis] || []).forEach((pt) => {
        const xVal = pt[0];
        if (xMin !== void 0 && xVal < xMin || xMax !== void 0 && xVal > xMax) {
          return;
        }
        xSet.add(xVal);
        yValues[serieIndex][xVal] = Number.isFinite(pt[1]) ? pt[1] : null;
      });
    });
    const xValues = Array.from(xSet);
    xValues.sort((a, b) => a - b);
    const yValuesArray = Object.values(yValues).map((yValue) => {
      return xValues.map((xValue) => yValue[xValue] != null ? yValue[xValue] : null);
    });
    return [xValues, ...yValuesArray];
  }, [series, xAxis, xRange]);
  const xTickValues = useMemo(() => {
    if (xAxis === XAxisDomain.Time) {
      const timeRange = xRange == null ? void 0 : xRange[XAxisDomain.Time];
      const timeDelta = timeRange ? (timeRange[1] || 0) - (timeRange[0] || 0) : chartData[0][chartData[0].length - 1] - chartData[0][0];
      if (timeDelta < 43200) {
        return getTimeTickValues;
      }
    }
  }, [chartData, xAxis, xRange]);
  const chartOptions = useMemo(() => {
    const plugins = propPlugins ?? [
      tooltipsPlugin({
        closeOnMouseExit: true,
        isShownEmptyVal: false,
        // use specified color on Serie, or glasbeyColor
        seriesColors
      }),
      closestPointPlugin({
        onPointClick,
        onPointFocus,
        yScale: "y"
      })
    ];
    return {
      axes: [
        {
          font: "12px Inter, Arial, Helvetica, sans-serif, system-ui",
          grid: { show: false },
          incrs: xAxis === XAxisDomain.Time ? void 0 : [
            /* eslint-disable array-element-newline */
            1,
            2,
            3,
            4,
            5,
            10,
            25,
            50,
            100,
            250,
            500,
            1e3,
            2500,
            5e3,
            1e4,
            25e3,
            5e4,
            1e5,
            25e4,
            5e5,
            1e6,
            25e5,
            5e6
            /* eslint-enable array-element-newline */
          ],
          label: xLabel,
          scale: "x",
          side: 2,
          space: 120,
          ticks: { show: false },
          values: xTickValues
        },
        {
          font: "12px Inter, Arial, Helvetica, sans-serif, system-ui",
          grid: { stroke: "#E3E3E3", width: 1 },
          label: yLabel,
          labelGap: 8,
          scale: "y",
          side: 3,
          size: 55,
          ticks: { show: false },
          values: yTickValues
        }
      ],
      cursor: {
        drag: { x: true, y: false }
      },
      height: height - (hasPopulatedSeries ? 0 : 20),
      key: optionKey,
      legend: { live: false, show: showLegend },
      plugins,
      scales: {
        x: {
          range: (_, min, max) => {
            var _a, _b;
            const r = (xRange == null ? void 0 : xRange[xAxis]) ? [
              Math.max(min, ((_a = xRange == null ? void 0 : xRange[xAxis]) == null ? void 0 : _a[0]) ?? min),
              Math.min(max, ((_b = xRange == null ? void 0 : xRange[xAxis]) == null ? void 0 : _b[1]) ?? max)
            ] : [min, max];
            return r;
          },
          time: xAxis === XAxisDomain.Time
        },
        y: {
          distr: scale === Scale.Log ? 3 : 1
        }
      },
      series: [
        { label: xLabel ?? xAxis ?? "X" },
        ...series.map((serie, idx) => {
          return {
            alpha: focusedSeries === void 0 || focusedSeries === idx ? 1 : 0.4,
            label: serie.name,
            points: { show: (serie.data[xAxis] || []).length <= 1 },
            scale: "y",
            spanGaps: true,
            stroke: seriesColors[idx],
            type: "line",
            width: 2
          };
        })
      ]
    };
  }, [
    seriesColors,
    onPointClick,
    onPointFocus,
    xLabel,
    xTickValues,
    yLabel,
    yTickValues,
    height,
    xAxis,
    xRange,
    scale,
    series,
    hasPopulatedSeries,
    propPlugins,
    focusedSeries,
    optionKey,
    showLegend
  ]);
  return /* @__PURE__ */ jsxs(Surface, { children: [
    title && /* @__PURE__ */ jsx("h5", { className: css.chartTitle, children: title }),
    /* @__PURE__ */ jsx(
      UPlotChart,
      {
        allowDownload: hasPopulatedSeries,
        data: chartData,
        handleError,
        isLoading,
        options: chartOptions,
        xAxis
      }
    )
  ] });
};
const ChartGrid = React__default.memo(
  ({
    chartsProps: propChartsProps,
    xAxis,
    onXAxisChange,
    scale,
    setScale,
    handleError
  }) => {
    const {
      themeSettings: { className: themeClass }
    } = useTheme();
    const scrollingContainer = useRef(null);
    const classes = [css.gridBase, themeClass];
    const chartsProps = Loadable.ensureLoadable(propChartsProps).getOrElse([]).filter(
      (c) => (
        // filter out Loadable series which are Loaded yet have no serie with more than 0 points.
        !Loadable.isLoadable(c.series) || !Loadable.isLoaded(c.series) || Loadable.getOrElse([], c.series).find(
          (serie) => Object.entries(serie.data).find(([, points]) => points.length > 0)
        )
      )
    );
    const isLoading = Loadable.isLoadable(propChartsProps) && Loadable.isNotLoaded(propChartsProps);
    const xAxisOptions = useMemo(() => {
      const xOpts = /* @__PURE__ */ new Set();
      chartsProps.forEach((chart) => {
        const series = Loadable.ensureLoadable(chart.series).getOrElse([]);
        series.forEach((serie) => {
          Object.entries(serie.data).forEach(([xAxisOption, dataPoints]) => {
            if (dataPoints.length > 0) {
              xOpts.add(xAxisOption);
            }
          });
        });
      });
      return Array.from(xOpts).sort();
    }, [chartsProps]);
    if (chartsProps.length === 0 && !isLoading)
      return /* @__PURE__ */ jsx(Message, { icon: "warning", title: "No data available." });
    return /* @__PURE__ */ jsx("div", { className: classes.join(" "), ref: scrollingContainer, children: /* @__PURE__ */ jsx(Spinner, { center: true, spinning: isLoading, tip: "Loading chart data...", children: chartsProps.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
      /* @__PURE__ */ jsx("div", { className: css.filterContainer, children: /* @__PURE__ */ jsxs(Row, { gap: 16, justifyContent: "end", children: [
        /* @__PURE__ */ jsx(ScaleSelect, { value: scale, onChange: setScale }),
        xAxisOptions && xAxisOptions.length > 1 && /* @__PURE__ */ jsx(XAxisFilter, { options: xAxisOptions, value: xAxis, onChange: onXAxisChange })
      ] }) }),
      /* @__PURE__ */ jsx(SyncProvider, { children: /* @__PURE__ */ jsx(
        VirtuosoGrid,
        {
          customScrollParent: scrollingContainer.current || void 0,
          data: chartsProps,
          itemClassName: css.gridItem,
          itemContent: (i, chartProps) => /* @__PURE__ */ jsx(
            LineChart,
            {
              ...chartProps,
              handleError,
              scale,
              xAxis
            },
            i
          ),
          listClassName: css.gridContainer
        }
      ) })
    ] }) }) });
  }
);
export {
  ChartGrid,
  LineChart,
  TRAINING_SERIES_COLOR,
  VALIDATION_SERIES_COLOR,
  LineChart as default
};
