"use strict";

/**
 * Match the unitOfMeasurement's string representation of a symbol to an actual symbol, where necessary
 * @param {String} unitOfMeasurementSymbolString String representation of the unitOfMeasurement's symbol
 * @returns {String} The unitOfMeasurement's symbol
 */
const matchUnitOfMeasurementSymbolStringToSymbol = function (
  unitOfMeasurementSymbolString
) {
  // Symbol - temperature
  if (unitOfMeasurementSymbolString === "degC") {
    return "\u00B0C";
  }
  // Symbol - flow rate
  else if (unitOfMeasurementSymbolString === "m3/h") {
    return "m\u00B3/h";
  }
  // If no symbol exists
  else {
    return unitOfMeasurementSymbolString;
  }
};

/**
 * Extract the phenomenon name from a Datastream's name
 * @param {String} datastreamName A string representing the Datastream's name
 * @returns {String} The extracted phenomenon name
 */
const extractPhenomenonNameFromDatastreamName = function (datastreamName) {
  const regex = /\/ (.*) DS/;
  return datastreamName.match(regex)[1]; // use second element in array
};

/**
 * Extract the building Id and phenomenon name from a Datastream's name
 * @param {String} datastreamName A string representing the Datastream's name
 * @returns {String} The extracted building ID and phenomenon name
 */
const extractBuildingIdPhenomenonNameFromDatastreamName = function (
  datastreamName
) {
  // The negative index should remove these nine characters: ` DS:60min`
  return datastreamName.slice(0, -9);
};

/**
 * Format the response containing a Datastream's metadata from Sensorthings API
 * @param {Object} datastreamMetadata An object containing a Datastream's metadata
 * @returns {Object} An object containing the formatted metadata that is suitable for use in a chart
 */
const formatDatastreamMetadataForChart = function (datastreamMetadata) {
  const {
    description: datastreamDescription,
    name: datastreamName,
    unitOfMeasurement,
  } = datastreamMetadata;

  // Extract phenomenon name from Datastream name
  const phenomenonName =
    extractPhenomenonNameFromDatastreamName(datastreamName);

  // Extract building ID + phenomenon name from Datastream name
  const buildingIdPhenomenonName =
    extractBuildingIdPhenomenonNameFromDatastreamName(datastreamName);

  // Get the unitOfMeasurement's symbol
  const unitOfMeasurementSymbol = matchUnitOfMeasurementSymbolStringToSymbol(
    unitOfMeasurement.symbol
  );

  return {
    datastreamDescription,
    datastreamName,
    phenomenonName,
    buildingIdPhenomenonName,
    unitOfMeasurementSymbol,
  };
};

/**
 * 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
 * @param {Boolean} isMetadataForAggregation A flag to determine if the datastream metadata will be used for aggregation. Set to `true` if metadata will be used for aggregation, `false` if not
 * @param {String} [aggregationInterval] The aggregation interval as a string, either "daily" or "monthly". Required when `isMetadataForAggregation = true`
 * @param {String} [aggregationType] The aggregation type as a string, either "sum" or "average". Required when `isMetadataForAggregation = true`
 * @returns {Object} An object that contains array(s) of formatted datastream metadata properties
 */
const extractPropertiesFromFormattedDatastreamMetadata = function (
  formattedDatastreamsMetadataArr,
  isMetadataForAggregation,
  aggregationInterval,
  aggregationType
) {
  if (
    formattedDatastreamsMetadataArr === undefined ||
    isMetadataForAggregation === undefined
  ) {
    throw new Error(
      "This function expects two arguments, ensure that both have been supplied"
    );
  } else if (
    formattedDatastreamsMetadataArr &&
    isMetadataForAggregation &&
    (aggregationInterval === undefined || aggregationType === undefined)
  ) {
    throw new Error(
      "This function expects four arguments, ensure that all of them have been supplied"
    );
  } else if (
    isMetadataForAggregation &&
    aggregationInterval !== "daily" &&
    aggregationInterval !== "monthly"
  ) {
    throw new Error(
      `The supported aggegation interval strings are "daily" or "monthly"`
    );
  } else if (
    isMetadataForAggregation &&
    aggregationType !== "minimum" &&
    aggregationType !== "maximum" &&
    aggregationType !== "sum" &&
    aggregationType !== "average"
  ) {
    throw new Error(
      `The supported aggegation type strings are "minimum", "maximum", "sum" or "average"`
    );
  }

  // 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 buildingIdsPhenomenonNamesArr = formattedDatastreamsMetadataArr.map(
    (datastreamMetadata) => datastreamMetadata.buildingIdPhenomenonName
  );

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

  // Case 1: Metadata NOT USED for aggregation; "isMetadataForAggregation" = false
  if (!isMetadataForAggregation) {
    return {
      datastreamDescriptionsArr,
      datastreamNamesArr,
      phenomenonNamesArr,
      buildingIdsPhenomenonNamesArr,
      unitOfMeasurementSymbolsArr,
    };
  }
  // Case 2: Metadata USED for aggregation; "isMetadataForAggregation" = true
  else {
    return {
      datastreamDescriptionsArr,
      datastreamNamesArr,
      phenomenonNamesArr,
      buildingIdsPhenomenonNamesArr,
      unitOfMeasurementSymbolsArr,
      aggregationInterval,
      aggregationType,
    };
  }
};

export {
  extractPhenomenonNameFromDatastreamName,
  formatDatastreamMetadataForChart,
  extractPropertiesFromFormattedDatastreamMetadata,
};