"use strict";

import {
  chartExportOptions,
  createFullTitleForLineOrColumnChart,
  createSubtitleForChart,
  createTooltipDateString,
} from "./chartHelpers.mjs";

/**
 * Format a computed aggregation result to make it suitable for a column chart
 * @param {Array} calendarDatesMonthsStrArr An array of unique calendar dates strings (in "YYYY-MM-DD" fromat) or unique calendar months strings (in "YYYY-MM" format)
 * @param {Array} aggregatedValuesArr An array of aggregated values
 * @returns {Array} An array of formatted aggregation values suitable for use in a column chart
 */
const formatAggregationResultForColumnChart = function (
  calendarDatesMonthsStrArr,
  aggregatedValuesArr
) {
  if (!calendarDatesMonthsStrArr || !aggregatedValuesArr) return;

  // Create an array of Unix timestamp strings
  const timestampsArr = calendarDatesMonthsStrArr.map((calendarStr) =>
    new Date(calendarStr).getTime()
  );

  // Combine timestamp and value pairs
  // The timestamps array and values array have same lengths, use one for looping
  return timestampsArr.map((timestamp, i) => [
    timestamp,
    aggregatedValuesArr[i],
  ]);
};

/**
 * Creates an options object for each series drawn in a column chart
 * @param {Array} formattedAggregatedResultForColumnChart An array of formatted aggregated result array(s) from one or more datastreams
 * @param {Array} buildingIdsPhenomenonNamesArr An array of string(s) made up of building ID(s) + phenomenon name(s)
 * @returns {Array} An array made up of series options object(s)
 */
const createSeriesOptionsForColumnChart = function (
  formattedAggregatedResultForColumnChart,
  buildingIdsPhenomenonNamesArr
) {
  // Create an array of seriesOptions objects
  // Assumes that the observation array of arrays, phenomenon names array and phenomenon symbols array are of equal length
  // Use one of the arrays for looping
  if (
    formattedAggregatedResultForColumnChart.length !==
    buildingIdsPhenomenonNamesArr.length
  ) {
    throw new Error(
      "The observations array and phenomenon names array have different lengths"
    );
  } else {
    return formattedAggregatedResultForColumnChart.map(
      (formattedAggResArray, i) => {
        return {
          name: `${buildingIdsPhenomenonNamesArr[i]}`,
          data: formattedAggResArray,
          turboThreshold: Number.MAX_VALUE, // #3404, remove after 4.0.5 release
        };
      }
    );
  }
};

/**
 * Draw a column chart using Highcharts library
 * @param {Array} formattedAggResultArraysForColumnChart An array made up of formatted aggregated result array(s) suitable for use in a column chart
 * @param {Object} extractedFormattedDatastreamProperties An object that contains arrays of formatted Datastream properties
 * @returns {undefined} undefined
 */
const drawColumnChartHighcharts = function (
  formattedAggResultArraysForColumnChart,
  extractedFormattedDatastreamProperties
) {
  // Formatted datastream properties
  let datastreamNamesArr,
    phenomenonNamesArr,
    buildingIdsPhenomenonNamesArr,
    unitOfMeasurementSymbolsArr,
    aggregationInterval,
    aggregationType;

  // Check whether the datastream properties are for aggregated observations
  // Case 1: No aggregation
  if (extractedFormattedDatastreamProperties?.aggregationType === undefined) {
    ({
      datastreamNamesArr,
      phenomenonNamesArr,
      buildingIdsPhenomenonNamesArr,
      unitOfMeasurementSymbolsArr,
    } = extractedFormattedDatastreamProperties);
  }
  // Case 2: Aggregation
  else {
    ({
      datastreamNamesArr,
      phenomenonNamesArr,
      buildingIdsPhenomenonNamesArr,
      unitOfMeasurementSymbolsArr,
      aggregationInterval,
      aggregationType,
    } = extractedFormattedDatastreamProperties);
  }

  // Create the array of series options object(s)
  const seriesOptionsArr = createSeriesOptionsForColumnChart(
    formattedAggResultArraysForColumnChart,
    buildingIdsPhenomenonNamesArr
  );

  // Assume that we will be comparing similar phenomena, so we can use the first phenomenon name
  const phenomenonName = phenomenonNamesArr[0];

  // Assume that we will be comparing similar phenomena, so we can use the first phenomenon symbol
  const unitOfMeasurementSymbol = unitOfMeasurementSymbolsArr[0];

  const textChartTitle = createFullTitleForLineOrColumnChart(
    phenomenonNamesArr,
    aggregationInterval,
    aggregationType
  );

  const textChartSubtitle = createSubtitleForChart(datastreamNamesArr);

  Highcharts.chart("chart-column", {
    chart: {
      type: "column",
      zoomType: "x",
    },

    title: {
      text: textChartTitle,
      "align": "center",
    },

    subtitle: {
      text: textChartSubtitle,
      "align": "center",
    },

    xAxis: {
      type: "datetime",
      crosshair: true,
    },

    yAxis: {
      title: {
        text: `${phenomenonName} [${unitOfMeasurementSymbol}]`,
      },
    },

    tooltip: {
      formatter() {
        // Our tooltip is shared
        // this.x -- common for all points
        // this.points -- an array containing properties for each series
        // Note that our `reduce` method is in this format:
        // ((previousValue, currentValue, currentIndex) => {...}, initialValue)
        return this.points.reduce(
          (previousValue, point, i) =>
            `${previousValue} <br/> <span style="color:${point.color}">${
              point.series.name
            }</span>: <b>${point.y.toFixed(2)} ${
              unitOfMeasurementSymbolsArr[i]
            }</b>`,
          `${createTooltipDateString(this.x, aggregationInterval)}`
        );
      },
      shared: true,
    },

    plotOptions: {
      column: {
        pointPadding: 0.2,
        borderWidth: 0,
      },
    },

    exporting: chartExportOptions,

    series: seriesOptionsArr,
  });
};

export { formatAggregationResultForColumnChart, drawColumnChartHighcharts };
