"use strict";

/**
 * Format the response from SensorThings API to make it suitable for use in a line chart
 * @param {Array} obsArray Array of observations (timestamp + value) that is response from SensorThings API
 * @returns {Array} Array of formatted observations suitable for use in a line chart
 */
const formatSensorThingsApiResponseForLineChart = function (obsArray) {
  if (!obsArray) return;

  const dataSTAFormatted = obsArray.map((result) => {
    const timestampObs = new Date(result[0].slice(0, -1)).getTime(); // slice() removes trailing "Z" character in timestamp
    const valueObs = result[1];
    return [timestampObs, valueObs];
  });

  return dataSTAFormatted;
};

/**
 * Extract the properties that make up the formatted datastream metadata object(s)
 * @param {Array} formattedDatastreamsMetadataArr An array of formatted metadata object(s) from one or more datastreams
 * @returns {Object} An object that contains array(s) of formatted datastream metadata properties
 */
const extractPropertiesFromDatastreamMetadata = function (
  formattedDatastreamsMetadataArr
) {
  // Create arrays from the properties of the formatted datastream metadata
  const datastreamDescriptionsArr = formattedDatastreamsMetadataArr.map(
    (datastreamMetadata) => datastreamMetadata.datastreamDescription
  );

  const datastreamNamesArr = formattedDatastreamsMetadataArr.map(
    (datastreamMetadata) => datastreamMetadata.datastreamName
  );

  const phenomenonNamesArr = formattedDatastreamsMetadataArr.map(
    (datastreamMetadata) => datastreamMetadata.phenomenonName
  );

  const unitOfMeasurementSymbolsArr = formattedDatastreamsMetadataArr.map(
    (datastreamMetadata) => datastreamMetadata.unitOfMeasurementSymbol
  );

  return {
    datastreamDescriptionsArr,
    datastreamNamesArr,
    phenomenonNamesArr,
    unitOfMeasurementSymbolsArr,
  };
};

/**
 * Extracts the sampling rate substring from a datastream name string
 * @param {Array} datastreamNamesArr An array of datastream name(s)
 * @returns {Array} An array containing the sampling rate substring(s)
 */
const extractSamplingRateFromDatastreamName = function (datastreamNamesArr) {
  // The sampling rate string is the last word in the Datastream name string
  return datastreamNamesArr.map((datastreamName) =>
    datastreamName.split(" ").pop()
  );
};

/**
 * Concatenates metadata properties to create a string for either the title or subtitle of a line chart
 * @param {Array} datastreamMetadataPropArr An array of metadata property strings
 * @returns {String} A string of comma separated metadata property strings
 */
const createCombinedTextForLineChartTitles = function (
  datastreamMetadataPropArr
) {
  return datastreamMetadataPropArr.join(", ");
};

/**
 * Creates an options object for each series drawn in the line chart
 * @param {Array} formattedObsArraysForLineChart An array of formatted observation array(s) from one or more datastreams
 * @param {Array} phenomenonNamesArr An array of phenomenon name(s)
 * @param {Array} phenomenonSymbolsArr An array of phenomenon symbol(s)
 * @returns {Array} An array made up of series options object(s)
 */
const createSeriesOptionsForLineChart = function (
  formattedObsArraysForLineChart,
  phenomenonNamesArr,
  phenomenonSymbolsArr
) {
  // An array of colors provided by the Highcharts object
  const seriesColors = Highcharts.getOptions().colors;

  // 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
  return formattedObsArraysForLineChart.map((formattedObsArray, i) => {
    return {
      name: `${phenomenonNamesArr[i]} (${phenomenonSymbolsArr[i]})`,
      data: formattedObsArray,
      color: seriesColors[i],
      turboThreshold: Number.MAX_VALUE, // #3404, remove after 4.0.5 release
    };
  });
};

/**
 * Draw a line chart using Highcharts library
 * @param {Array} formattedObsArraysForLineChart An array made up of formatted observation array(s) suitable for use in a line chart
 * @param {Object} formattedDatastreamMetadataArr An array made up of object(s) containing Datastream metadata
 * @returns {undefined} undefined
 */
const drawLineChartHighcharts = function (
  formattedObsArraysForLineChart,
  formattedDatastreamMetadataArr
) {
  // Arrays of datastream properties
  const {
    datastreamNamesArr,
    phenomenonNamesArr,
    unitOfMeasurementSymbolsArr,
  } = extractPropertiesFromDatastreamMetadata(formattedDatastreamMetadataArr);

  // Create the array of series options object(s)
  const seriesOptionsArr = createSeriesOptionsForLineChart(
    formattedObsArraysForLineChart,
    phenomenonNamesArr,
    unitOfMeasurementSymbolsArr
  );

  Highcharts.stockChart("chart-line", {
    chart: {
      zoomType: "x",
    },

    rangeSelector: {
      selected: 5,
    },

    title: {
      text: createCombinedTextForLineChartTitles(phenomenonNamesArr),
      "align": "left",
    },

    subtitle: {
      text: `Sampling rate(s): ${createCombinedTextForLineChartTitles(
        extractSamplingRateFromDatastreamName(datastreamNamesArr)
      )}`,
      align: "left",
    },

    tooltip: {
      pointFormat:
        '<span style="color:{series.color}">{series.name}</span>: <b>{point.y}</b> <br/>',
      valueDecimals: 2,
    },

    series: seriesOptionsArr,
  });
};

export { formatSensorThingsApiResponseForLineChart, drawLineChartHighcharts };