import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray';
import _defineProperty from '@babel/runtime/helpers/defineProperty';
import capitalize from '../../node_modules/lodash-es/capitalize.js';
import filter from '../../node_modules/lodash-es/filter.js';
import _omit from '../../node_modules/lodash-es/omit.js';
import _merge from '../../node_modules/lodash-es/merge.js';
import isNil from '../../node_modules/lodash-es/isNil.js';
import isEmpty from '../../node_modules/lodash-es/isEmpty.js';
import 'core-js/modules/es.array.concat.js';
import 'core-js/modules/es.array.filter.js';
import 'core-js/modules/es.array.find.js';
import 'core-js/modules/es.array.iterator.js';
import 'core-js/modules/es.array.map.js';
import 'core-js/modules/es.object.get-own-property-descriptor.js';
import 'core-js/modules/es.object.get-own-property-descriptors.js';
import 'core-js/modules/es.object.keys.js';
import 'core-js/modules/es.symbol.js';
import 'core-js/modules/es.object.to-string.js';
import 'core-js/modules/es.set.js';
import 'core-js/modules/es.string.iterator.js';
import 'core-js/modules/web.dom-collections.for-each.js';
import 'core-js/modules/web.dom-collections.iterator.js';
import { useMemo } from 'react';
import { chartValueFormatter, handleTooltip, getUpdatedCardSize } from '../../utils/cardUtilityFunctions.js';
import { CHART_COLORS } from '../../constants/CardPropTypes.js';
import { formatGraphTick } from '../TimeSeriesCard/timeSeriesUtils.js';
import { TIME_SERIES_TYPES, CARD_SIZES } from '../../constants/LayoutConstants.js';
import dayjs from '../../utils/dayjs.js';

function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }

/**
 * Formats and maps the colors to their corresponding datasets in the carbon charts tabular data format
 * @param {Array} series an array of dataset group classifications
 * @returns {Object} colors - formatted
 */
var formatColors = function formatColors() {
  var series = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
  var colors = {
    scale: {}
  };
  if (Array.isArray(series)) {
    series.forEach(function (dataset, index) {
      colors.scale[dataset.label] = dataset.color || CHART_COLORS[index % CHART_COLORS.length];
    });
  } else {
    colors.scale[series.label] = series.color || CHART_COLORS[0];
  }
  return colors;
};

/**
 * Configures the axes object for the comboChart
 */

var configureAxes = function configureAxes(content) {
  var domainRange = content.domainRange,
    xLabel = content.xLabel,
    yLabel = content.yLabel,
    unit = content.unit,
    chartType = content.chartType,
    decimalPrecision = content.decimalPrecision,
    includeZeroOnXaxis = content.includeZeroOnXaxis,
    interval = content.interval,
    locale = content.locale,
    series = content.series,
    showTimeInGMT = content.showTimeInGMT,
    size = content.size,
    includeZeroOnYaxis = content.includeZeroOnYaxis,
    previousTick = content.previousTick,
    thresholds = content.thresholds;

  /** *
   * timestamp of current value
   * index of current value
   * ticks: array of current ticks or a single string with part of the date, e.g. month or year & month
   */
  var formatTick = function formatTick(timestamp, index, ticks) {
    var previousTimestamp = previousTick.current;
    // store current in the previous tick
    previousTick.current = timestamp;
    return formatGraphTick(timestamp, index, ticks, interval, locale, previousTimestamp, showTimeInGMT);
  };

  // Checks size property against new size naming convention and reassigns to closest supported size if necessary.
  var newSize = getUpdatedCardSize(size);
  var getMaxTicksPerSize = function getMaxTicksPerSize(s) {
    switch (s) {
      case CARD_SIZES.MEDIUMTHIN:
        return 2;
      case CARD_SIZES.MEDIUM:
        return 4;
      case CARD_SIZES.MEDIUMWIDE:
      case CARD_SIZES.LARGE:
        return 6;
      case CARD_SIZES.LARGEWIDE:
        return 14;
      default:
        return 10;
    }
  };
  return {
    bottom: _objectSpread({
      title: xLabel || ' ',
      mapsTo: 'date',
      scaleType: 'time',
      ticks: {
        max: getMaxTicksPerSize(newSize),
        formatter: formatTick
      },
      includeZero: includeZeroOnXaxis
    }, domainRange ? {
      domain: domainRange
    } : {}),
    left: {
      title: "".concat(yLabel || '', " ").concat(unit ? "(".concat(unit, ")") : ''),
      mapsTo: 'value',
      ticks: {
        formatter: function formatter(axisValue) {
          return chartValueFormatter(axisValue, newSize, null, locale, decimalPrecision);
        }
      },
      stacked: chartType === TIME_SERIES_TYPES.BAR && series.length > 1,
      includeZero: includeZeroOnYaxis,
      scaleType: 'linear',
      thresholds: thresholds
    }
  };
};

/**
 * Translates our raw data into a language the carbon-charts understand
 * @param {string} timeDataSourceId, the field that identifies the timestamp value in the data
 * @param {array} series, an array of lines to create in our chart
 * @param {array} values, the array of values from our data layer
 *
 * TODO: Handle empty data lines gracefully and notify the user of data lines that did not
 * match the dataFilter
 *
 * @returns {object} with a labels array and a datasets array
 */

var useChartData = function useChartData(values, _ref) {
  var _ref$series = _ref.series,
    series = _ref$series === void 0 ? [] : _ref$series,
    timeDataSourceId = _ref.timeDataSourceId,
    showTimeInGMT = _ref.showTimeInGMT;
  // Carbon charts is incredibly slow with large datasets sometimes, so let's shave off a little time where we can
  return useMemo(function () {
    // Generate a set of unique timestamps for the values
    var timestamps = _toConsumableArray(new Set(values.map(function (val) {
      return val[timeDataSourceId];
    })));
    var data = [];
    var seriesArray = Array.isArray(series) ? series : [series];

    // Series is the different groups of datasets
    seriesArray.forEach(function (_ref2) {
      var dataSourceId = _ref2.dataSourceId,
        _ref2$dataFilter = _ref2.dataFilter,
        dataFilter = _ref2$dataFilter === void 0 ? {} : _ref2$dataFilter,
        label = _ref2.label;
      timestamps.forEach(function (timestamp) {
        // First filter based on on the dataFilter
        var filteredData = filter(values, dataFilter);
        if (!isEmpty(filteredData)) {
          // have to filter out null values from the dataset, as it causes Carbon Charts to break
          filteredData.filter(function (dataItem) {
            // only allow valid timestamp matches
            return !isNil(dataItem[timeDataSourceId]) && dataItem[timeDataSourceId] === timestamp;
          }).forEach(function (dataItem) {
            // Check to see if the data Item actually exists in this timestamp before adding to data (to support sparse data in the values)
            if (dataItem[dataSourceId]) {
              data.push({
                date: dataItem[timeDataSourceId] instanceof Date ? dataItem[timeDataSourceId] : showTimeInGMT ? dayjs.utc(dataItem[timeDataSourceId]) : dayjs(dataItem[timeDataSourceId]),
                value: dataItem[dataSourceId],
                group: label
              });
            }
          });
        }
      });
    });
    return data;
  }, [values, series, timeDataSourceId, showTimeInGMT]);
};
var useChartOptions = function useChartOptions(content) {
  return useMemo(function () {
    var comboChartTypes = content.comboChartTypes,
      decimalPrecision = content.decimalPrecision,
      i18n = content.i18n,
      isEditable = content.isEditable,
      isLoading = content.isLoading,
      locale = content.locale,
      series = content.series,
      showTimeInGMT = content.showTimeInGMT,
      size = content.size,
      timeDataSourceId = content.timeDataSourceId,
      tooltipDateFormatPattern = content.tooltipDateFormatPattern,
      defaultDateFormatPattern = content.defaultDateFormatPattern,
      unit = content.unit,
      values = content.values;
    var options = {
      experimental: true,
      animations: false,
      accessibility: true,
      axes: configureAxes(content),
      legend: {
        position: 'bottom',
        enabled: values.length > 1,
        clickable: !isEditable
      },
      containerResizable: true,
      comboChartTypes: comboChartTypes,
      series: series,
      color: formatColors(series),
      timeScale: {
        addSpaceOnEdges: 0
      },
      tooltip: {
        valueFormatter: function valueFormatter(tooltipValue) {
          return chartValueFormatter(tooltipValue, size, unit, locale, decimalPrecision);
        },
        customHTML: function customHTML() {
          for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
            args[_key] = arguments[_key];
          }
          return handleTooltip.apply(void 0, args.concat([timeDataSourceId, showTimeInGMT, tooltipDateFormatPattern, locale]));
        },
        groupLabel: i18n.tooltipGroupLabel,
        totalLabel: i18n.tooltipTotalLabel
      },
      toolbar: {
        enabled: false
      },
      defaultDateFormatPattern: defaultDateFormatPattern
    };
    options.data = _merge(options.data, {
      loading: isLoading
    });
    return _objectSpread(_objectSpread({}, options), content);
  }, [content]);
};
var extractDataAndColumnNames = function extractDataAndColumnNames(values, chartOptions) {
  var timeDataSourceId = chartOptions.timeDataSourceId,
    showTimeInGMT = chartOptions.showTimeInGMT,
    defaultDateFormatPattern = chartOptions.defaultDateFormatPattern;
  var maxColumnNames = [];
  var tableValues = values.map(function (value, index) {
    var currentValueColumns = Object.keys(_omit(value, timeDataSourceId));
    maxColumnNames = currentValueColumns.length > maxColumnNames.length ? currentValueColumns : maxColumnNames;
    return {
      id: "dataindex-".concat(index),
      values: _objectSpread(_objectSpread({}, _omit(value, timeDataSourceId)), {}, _defineProperty({}, timeDataSourceId, (showTimeInGMT ? dayjs.utc(value[timeDataSourceId]) : dayjs(value[timeDataSourceId])).format(defaultDateFormatPattern))),
      isSelectable: false
    };
  });
  return {
    tableData: tableValues,
    columnNames: maxColumnNames
  };
};
var useTableData = function useTableData(values, chartOptions) {
  var _useMemo = useMemo(function () {
      return extractDataAndColumnNames(values, chartOptions);
    }, [values, chartOptions]),
    tableData = _useMemo.tableData;
  return tableData;
};
var useTableColumns = function useTableColumns(values, chartOptions) {
  var timeDataSourceId = chartOptions.timeDataSourceId,
    decimalPrecision = chartOptions.decimalPrecision,
    i18n = chartOptions.i18n,
    size = chartOptions.size,
    series = chartOptions.series,
    unit = chartOptions.unit,
    locale = chartOptions.locale;
  var _extractDataAndColumn = extractDataAndColumnNames(values, chartOptions),
    columnNames = _extractDataAndColumn.columnNames;

  // In expanded mode we show the data underneath the linechart in a table so need to build the columns
  var tableColumns = useMemo(function () {
    // First column is timestamp
    var columns = [{
      id: timeDataSourceId,
      name: capitalize(timeDataSourceId),
      isSortable: true,
      type: 'TIMESTAMP'
    }];
    // then the rest in series order
    return columns.concat(columnNames.map(function (columnName) {
      var matchingDataSource = Array.isArray(series) ? series.find(function (d) {
        return d.dataSourceId === columnName;
      }) : series;
      return {
        id: columnName,
        // use the label if one exists as it will be the user-defined, readable name
        // UNLESS dataFilter is enabled as the matchingDataSource will only find the first match
        name: matchingDataSource ? matchingDataSource.dataFilter ? matchingDataSource.dataSourceId : matchingDataSource.label : columnName,
        isSortable: true,
        filter: {
          placeholderText: i18n.defaultFilterStringPlaceholdText
        },
        renderDataFunction: function renderDataFunction(_ref3) {
          var value = _ref3.value;
          if (typeof value === 'number' && !isNil(decimalPrecision)) {
            return chartValueFormatter(value, size, unit, locale, decimalPrecision);
          }
          return value;
        }
      };
    }));
  }, [columnNames, decimalPrecision, i18n.defaultFilterStringPlaceholdText, locale, series, size, timeDataSourceId, unit]);
  return tableColumns;
};

export { useChartData, useChartOptions, useTableColumns, useTableData };
