"use strict";

import { checkForAndDeleteUniqueObservationsFromLargerArray } from "./chartHelpers.mjs";

import { getMetadataPlusObservationsFromSingleOrMultipleDatastreams } from "./fetchData.mjs";

import { extractPhenomenonNameFromDatastreamName } from "./fetchedDataProcessing.mjs";

/**
 * Calculate the temperature difference, dT, between Vorlauf temperature [VL] and
 * Rücklauf temperature [RL] (i.e., dT = VL - RL). In addition, create synthetic metadata
 * for the temperature difference
 * @async
 * @param {String} baseUrl Base URL of the STA server
 * @param {Object} urlParams The URL parameters to be sent together with the GET request
 * @param {Array} buildingSamplingRateNestedArr A N*1 array (where N >= 1) containing a nested array of buildings & sampling rates as strings, i.e. [["101", "15min"]] or [["101", "15min"], ["102", "60min"]] or [["101", "15min"], ["102", "60min"], ["225", "60min"]], etc
 * @returns {Promise} A promise that contains a 1*2 array (the first element is an array that contans N Observations arrays; and the second element is an array of N Datastream metadata objects) when fulfilled
 */
export const calculateVorlaufMinusRuecklaufTemperature = async function (
  baseUrl,
  urlParams,
  buildingSamplingRateNestedArr
) {
  try {
    // Arrays to store our results
    const combinedObservationsArr = [];
    const combinedMetadataArr = [];

    const buildingDataPointSamplingRateNestedTwiceArr =
      buildingSamplingRateNestedArr.map((bldgSmplngRate) => {
        // The building ID is the first element, sampling rate is second element
        return [
          [bldgSmplngRate[0], "vl", bldgSmplngRate[1]],
          [bldgSmplngRate[0], "rl", bldgSmplngRate[1]],
        ];
      });

    // Note: We have to use a for/of loop here due to the asynchronous nature of our code
    for (const bldgDataPtSamplingRateNestedArr of buildingDataPointSamplingRateNestedTwiceArr) {
      // Use the first element of the nested array to extract building ID + sampling rate
      // Note: we skip the second element
      const [buildingId, , samplingRate] = bldgDataPtSamplingRateNestedArr[0];

      const BUILDING_ID = buildingId;
      const SAMPLING_RATE = samplingRate;

      const observationsPlusMetadata =
        await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
          baseUrl,
          urlParams,
          bldgDataPtSamplingRateNestedArr
        );

      // Extract Vorlauf temperature, Ruecklauf temperature and metadata
      const [
        [vorlaufTemperatureObsArr, ruecklaufTemperatureObsArr],
        [metadataVorlauf, metadataRuecklauf],
      ] = observationsPlusMetadata;

      // Compare the lengths of the observations arrays for VL and RL,
      // delete the unique observation(s), if necessary
      const [vorlaufTemperatureObsFinalArr, ruecklaufTemperatureObsFinalArr] =
        vorlaufTemperatureObsArr.length === ruecklaufTemperatureObsArr.length
          ? [vorlaufTemperatureObsArr, ruecklaufTemperatureObsArr]
          : checkForAndDeleteUniqueObservationsFromLargerArray(
              vorlaufTemperatureObsArr,
              ruecklaufTemperatureObsArr
            );

      // Extract the temperature values
      const vorlaufTemperatureValues = vorlaufTemperatureObsFinalArr.map(
        (vlTempObs) => vlTempObs[1]
      );
      const ruecklaufTemperatureValues = ruecklaufTemperatureObsFinalArr.map(
        (rlTempObs) => rlTempObs[1]
      );

      // The arrays have equal length, we need only use one of them for looping
      // Resulting array contains the following pairs (timestamp + dT)
      const vorlaufMinusRuecklaufTemperatureObs = vorlaufTemperatureObsArr.map(
        (vlTempObs, i) => {
          // Use timestamp from VL, since is equal to that of RL
          const timestamp = vlTempObs[0];

          // Case 1: One of the observation values is `null`,
          // no need to calculate temperature difference
          if (
            vorlaufTemperatureValues[i] === null ||
            ruecklaufTemperatureValues[i] === null
          ) {
            return [timestamp, null];
          }

          // Case 2: Neither of the observation values is `null`,
          // calculate temperature difference
          return [
            timestamp,
            vorlaufTemperatureValues[i] - ruecklaufTemperatureValues[i],
          ];
        }
      );

      // From Vorlauf metadata, extract `name` and `unitOfMeasurement`
      const {
        name: datastreamNameVorlauf,
        unitOfMeasurement: unitOfMeasurementVorlauf,
      } = metadataVorlauf;

      // From Ruecklauf metadata, extract `name`
      const { name: datastreamNameRuecklauf } = metadataRuecklauf;

      // Extract the phenomenon names from the Datastream names
      const phenomenonNameVorlauf = extractPhenomenonNameFromDatastreamName(
        datastreamNameVorlauf
      );
      const phenomenonNameRuecklauf = extractPhenomenonNameFromDatastreamName(
        datastreamNameRuecklauf
      );

      // Create our custom datastream description text
      // The resulting datastream description string has two `temperature` substrings;
      // replace the first occurence with an empty string
      const descriptionTempDifference =
        `Computed dT: ${phenomenonNameVorlauf} minus ${phenomenonNameRuecklauf}`.replace(
          "temperature",
          ""
        );

      // Create our custom datastream name text
      const nameTempDifference = `BOSCH_${BUILDING_ID} / dT Temperature difference (VL-RL) DS:${SAMPLING_RATE}`;

      // The datastream object that we return needs to have these property names
      const description = descriptionTempDifference;
      const name = nameTempDifference;
      const unitOfMeasurement = unitOfMeasurementVorlauf;

      // Add the observations and metadata to our arrays
      combinedObservationsArr.push(vorlaufMinusRuecklaufTemperatureObs);
      combinedMetadataArr.push({ description, name, unitOfMeasurement });
    }

    return [combinedObservationsArr, combinedMetadataArr];
  } catch (err) {
    console.error(err);
  }
};
