text: import { map, max, uniq, sortBy, flatten, find } from 'lodash';
  import { createNumberFormatter } from '@/lib/value-format';
  
  const defaultColorScheme = [
    [0, '#356aff'],
    [0.14, '#4a7aff'],
    [0.28, '#5d87ff'],
    [0.42, '#7398ff'],
    [0.56, '#fb8c8c'],
    [0.71, '#ec6463'],
    [0.86, '#ec4949'],
    [1, '#e92827'],
  ];
  
  function prepareSeries(series, options, additionalOptions) {
    const { colorScheme, formatNumber } = additionalOptions;
  
    const plotlySeries = {
      x: [],
      y: [],
      z: [],
      type: 'heatmap',
      name: '',
      colorscale: colorScheme,
    };
  
    plotlySeries.x = uniq(map(series.data, v => v.x));
    plotlySeries.y = uniq(map(series.data, v => v.y));
  
    if (options.sortX) {
      plotlySeries.x = sortBy(plotlySeries.x);
    }
  
    if (options.sortY) {
      plotlySeries.y = sortBy(plotlySeries.y);
    }
  
    if (options.reverseX) {
      plotlySeries.x.reverse();
    }
  
    if (options.reverseY) {
      plotlySeries.y.reverse();
    }
  
    const zMax = max(map(series.data, d => d.zVal));
  
    // Use text trace instead of default annotation for better performance
    const dataLabels = {
      x: [],
      y: [],
      mode: 'text',
      hoverinfo: 'skip',
      showlegend: false,
      text: [],
      textfont: {
        color: [],
      },
    };
  
    for (let i = 0; i < plotlySeries.y.length; i += 1) {
      const item = [];
      for (let j = 0; j < plotlySeries.x.length; j += 1) {
        const datum = find(
          series.data,
          { x: plotlySeries.x[j], y: plotlySeries.y[i] },
        );
  
        const zValue = datum && datum.zVal || 0;
        item.push(zValue);
  
        if (isFinite(zMax) && options.showDataLabels) {
          dataLabels.x.push(plotlySeries.x[j]);
          dataLabels.y.push(plotlySeries.y[i]);
          dataLabels.text.push(formatNumber(zValue));
          if (options.colorScheme && options.colorScheme === 'Custom...') {
            dataLabels.textfont.color.push('white');
          } else {
            dataLabels.textfont.color.push((zValue / zMax) < 0.25 ? 'white' : 'black');
          }
        }
      }
      plotlySeries.z.push(item);
    }
  
    if (isFinite(zMax) && options.showDataLabels) {
      return [plotlySeries, dataLabels];
    }
    return [plotlySeries];
  }
  
  export default function prepareHeatmapData(seriesList, options) {
    let colorScheme = [];
  
    if (!options.colorScheme) {
      colorScheme = defaultColorScheme;
    } else if (options.colorScheme === 'Custom...') {
      colorScheme = [[0, options.heatMinColor], [1, options.heatMaxColor]];
    } else {
      colorScheme = options.colorScheme;
    }
  
    const additionalOptions = {
      colorScheme,
      formatNumber: createNumberFormatter(options.numberFormat),
    };
  
    return flatten(map(seriesList, series => prepareSeries(series, options, additionalOptions)));
  }
  