"use strict";

import {
  BASE_URL,
  QUERY_PARAMS_COMBINED,
} from "./src_modules/baseUrlPlusQueryParams.mjs";

import {
  formatSensorThingsApiResponseForLineOrColumnChart,
  drawLineChartHighcharts,
} from "./src_modules/chartLine.mjs";

import {
  formatSensorThingsApiResponseForHeatMap,
  drawHeatMapHighcharts,
} from "./src_modules/chartHeatmap.mjs";

import {
  formatSensorThingsApiResponseForScatterPlot,
  drawScatterPlotHighcharts,
} from "./src_modules/chartScatterPlot.mjs";

import {
  formatAggregationResultForColumnChart,
  drawColumnChartHighcharts,
} from "./src_modules/chartColumn.mjs";

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

import {
  formatDatastreamMetadataForChart,
  extractPropertiesFromFormattedDatastreamMetadata,
} from "./src_modules/fetchedDataProcessing.mjs";

import { calculateVorlaufMinusRuecklaufTemperature } from "./src_modules/calculateTemperatureDiff.mjs";

import {
  extractObservationsWithinDatesInterval,
  extractUniqueCalendarDatesFromTimestamp,
  extractUniqueCalendarMonthsFromCalendarDates,
} from "./src_modules/aggregateHelpers.mjs";

import {
  calculateSumOfObservationValuesWithinInterval,
  calculateAverageOfObservationValuesWithinInterval,
} from "./src_modules/aggregate.mjs";

/**
 * Test plotting of temp difference (dT) using heatmap
 */
const drawHeatmapHCUsingTempDifference = async function () {
  try {
    const [observationsTemperatureDiff225Arr, metadataTemperatureDiff225Arr] =
      await calculateVorlaufMinusRuecklaufTemperature(
        BASE_URL,
        QUERY_PARAMS_COMBINED,
        "225",
        "60min"
      );

    // We want to have nested arrays, so as to mimick the nested responses we get from fetching observations + metadata
    const observationsTemperatureDiff225NestedArr = [
      observationsTemperatureDiff225Arr,
    ];

    const metadataTemperatureDiff225NestedArr = [metadataTemperatureDiff225Arr];

    // Format the observations
    const formattedTempDiff225NestedArr =
      observationsTemperatureDiff225NestedArr.map((obsArr) =>
        formatSensorThingsApiResponseForHeatMap(obsArr)
      );

    // Format the metadata
    const formattedTempDiff225MetadataNestedArr =
      metadataTemperatureDiff225NestedArr.map((metadataObj) =>
        formatDatastreamMetadataForChart(metadataObj)
      );

    // Extract the formatted metadata properties
    const extractedFormattedTempDiff225Properties =
      extractPropertiesFromFormattedDatastreamMetadata(
        formattedTempDiff225MetadataNestedArr,
        false
      );

    // First need to extract the formatted observations from the nested array
    // Heatmap only needs one set of formatted observation values
    drawHeatMapHighcharts(
      ...formattedTempDiff225NestedArr,
      extractedFormattedTempDiff225Properties
    );
  } catch (err) {
    console.error(err);
  }
};

/**
 * Test drawing of scatter plot chart
 */
const drawScatterPlotHCTest2 = async function () {
  try {
    const sensorsOfInterestNestedArr = [
      ["weather_station_521", "outside_temp", "60min"],
      ["225", "vl", "60min"],
      ["125", "rl", "60min"],
    ];

    const observationsPlusMetadata =
      await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
        BASE_URL,
        QUERY_PARAMS_COMBINED,
        sensorsOfInterestNestedArr
      );

    // Extract the combined arrays for observations and metadata
    const [observationsNestedArr, metadataNestedArr] = observationsPlusMetadata;

    // Extract values for x-axis and y-axis
    // x-axis values are first element of nested observations array
    const [obsXAxisArr] = observationsNestedArr.slice(0, 1);
    // y-axis values are rest of elements of nested observations array
    const obsYAxisNestedArr = observationsNestedArr.slice(1);

    // Create formatted array(s) for observations
    const formattedObservationsArr = obsYAxisNestedArr.map((obsYAxisArr) =>
      formatSensorThingsApiResponseForScatterPlot(obsXAxisArr, obsYAxisArr)
    );

    // Create formatted array(s) for metadata
    const formattedMetadataNestedArr = metadataNestedArr.map((metadataObj) =>
      formatDatastreamMetadataForChart(metadataObj, false)
    );

    // Extract the formatted metadata properties
    const extractedFormattedDatastreamProperties =
      extractPropertiesFromFormattedDatastreamMetadata(
        formattedMetadataNestedArr,
        false
      );

    drawScatterPlotHighcharts(
      formattedObservationsArr,
      extractedFormattedDatastreamProperties
    );
  } catch (err) {
    console.error(err);
  }
};

/**
 * Test drawing of line chart with multiple series
 */
const testLineChartMultipleSeries = async function () {
  try {
    const sensorsOfInterestNestedArr = [
      ["225", "vl", "60min"],
      ["125", "rl", "60min"],
      ["weather_station_521", "outside_temp", "60min"],
    ];

    const observationsPlusMetadataArr =
      await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
        BASE_URL,
        QUERY_PARAMS_COMBINED,
        sensorsOfInterestNestedArr
      );

    // Extract the observations and metadata arrays of arrays
    const [observationsNestedArr, metadataNestedArr] =
      observationsPlusMetadataArr;

    // Format the observations
    const formattedObservationsNestedArr = observationsNestedArr.map(
      (observationsArr) =>
        formatSensorThingsApiResponseForLineOrColumnChart(observationsArr)
    );

    // Format the metadata
    const formattedMetadataNestedArr = metadataNestedArr.map((metadataArr) =>
      formatDatastreamMetadataForChart(metadataArr)
    );

    // Extract the formatted metadata properties
    const extractedFormattedDatastreamProperties =
      extractPropertiesFromFormattedDatastreamMetadata(
        formattedMetadataNestedArr,
        false
      );

    drawLineChartHighcharts(
      formattedObservationsNestedArr,
      extractedFormattedDatastreamProperties
    );
  } catch (err) {
    console.error(err);
  }
};

/**
 * Test drawing of column chart using aggregation / sum result - monthly
 */
const drawColumnChartMonthlySumTest = async function () {
  try {
    const sensorsOfInterestNestedArr = [
      ["125", "vl", "60min"],
      ["225", "vl", "60min"],
    ];

    const observationsPlusMetadata =
      await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
        BASE_URL,
        QUERY_PARAMS_COMBINED,
        sensorsOfInterestNestedArr
      );

    // Extract the observations and metadata for each sensor
    // Array elements in same order as input array
    const [obsNestedArr, metadataNestedArr] = observationsPlusMetadata;

    // User-specified start date and end date
    const startDate = "2020-02-01";
    const endDate = "2020-05-31";

    // Extract observations within the user-specified start and end date
    const observationsNestedArr = obsNestedArr.map((obsArr) =>
      extractObservationsWithinDatesInterval(
        obsArr,
        "60min",
        startDate,
        endDate
      )
    );

    // Unique calendar dates
    const uniqueCalendarDatesNestedArr = observationsNestedArr.map(
      (observationsArr) =>
        extractUniqueCalendarDatesFromTimestamp(observationsArr)
    );

    // Unique calendar months
    const uniqueCalendarMonthsNestedArr = uniqueCalendarDatesNestedArr.map(
      (uniqueCalendarDatesArr) =>
        extractUniqueCalendarMonthsFromCalendarDates(uniqueCalendarDatesArr)
    );

    // Calculate sum of values of observations - monthly
    const observationsSumMonthlyNestedArr =
      calculateSumOfObservationValuesWithinInterval(
        observationsNestedArr,
        "60min",
        uniqueCalendarMonthsNestedArr,
        "monthly"
      );

    // Format the observations
    const formattedObservationsSumMonthlyNestedArr =
      observationsSumMonthlyNestedArr.map((obsSumMonthlyArr, i) =>
        formatAggregationResultForColumnChart(
          uniqueCalendarMonthsNestedArr[i],
          obsSumMonthlyArr
        )
      );

    // Format the metadata
    const formattedMetadataNestedArr = metadataNestedArr.map((metadataObj) =>
      formatDatastreamMetadataForChart(metadataObj)
    );

    // Extract the formatted metadata properties
    const extractedFormattedDatastreamProperties =
      extractPropertiesFromFormattedDatastreamMetadata(
        formattedMetadataNestedArr,
        true,
        "monthly",
        "sum"
      );

    drawColumnChartHighcharts(
      formattedObservationsSumMonthlyNestedArr,
      extractedFormattedDatastreamProperties
    );
  } catch (err) {
    console.error(err);
  }
};

/**
 * Test drawing of column chart using aggregation / sum result - daily
 */
const drawColumnChartDailySumTest = async function () {
  try {
    const sensorsOfInterestNestedArr = [
      ["125", "vl", "60min"],
      ["225", "vl", "60min"],
    ];

    const observationsPlusMetadata =
      await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
        BASE_URL,
        QUERY_PARAMS_COMBINED,
        sensorsOfInterestNestedArr
      );

    // Extract the observations and metadata for each sensor
    // Array elements in same order as input array
    const [obsNestedArr, metadataNestedArr] = observationsPlusMetadata;

    // User-specified start date and end date
    const startDate = "2020-02-01";
    const endDate = "2020-05-31";

    // Extract observations within the user-specified start and end date
    const observationsNestedArr = obsNestedArr.map((obsArr) =>
      extractObservationsWithinDatesInterval(
        obsArr,
        "60min",
        startDate,
        endDate
      )
    );

    // Unique calendar dates
    const uniqueCalendarDatesNestedArr = observationsNestedArr.map(
      (observationsArr) =>
        extractUniqueCalendarDatesFromTimestamp(observationsArr)
    );

    // Calculate sum of values of observations - daily
    const observationsSumDailyNestedArr =
      calculateSumOfObservationValuesWithinInterval(
        observationsNestedArr,
        "60min",
        uniqueCalendarDatesNestedArr,
        "daily"
      );

    // Format the observations - daily
    const formattedObservationsSumDailyNestedArr =
      observationsSumDailyNestedArr.map((obsSumDailyArr, i) =>
        formatAggregationResultForColumnChart(
          uniqueCalendarDatesNestedArr[i],
          obsSumDailyArr
        )
      );

    // Format the metadata
    const formattedMetadataNestedArr = metadataNestedArr.map((metadataObj) =>
      formatDatastreamMetadataForChart(metadataObj)
    );

    // Extract the formatted metadata properties
    const extractedFormattedDatastreamProperties =
      extractPropertiesFromFormattedDatastreamMetadata(
        formattedMetadataNestedArr,
        true,
        "daily",
        "sum"
      );

    drawColumnChartHighcharts(
      formattedObservationsSumDailyNestedArr,
      extractedFormattedDatastreamProperties
    );
  } catch (err) {
    console.error(err);
  }
};

/**
 * Test drawing of column chart using raw observations
 */
const drawColumnChartNonAggregationTest = async function () {
  try {
    const sensorsOfInterestNestedArr = [
      ["125", "vl", "60min"],
      ["225", "vl", "60min"],
    ];

    const observationsPlusMetadata =
      await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
        BASE_URL,
        QUERY_PARAMS_COMBINED,
        sensorsOfInterestNestedArr
      );

    // Extract the observations and metadata for each sensor
    // Array elements in same order as input array
    const [observationsNestedArr, metadataNestedArr] = observationsPlusMetadata;

    // Format the observations
    const formattedObservationsNestedArr = observationsNestedArr.map(
      (observationsArr) =>
        formatSensorThingsApiResponseForLineOrColumnChart(observationsArr)
    );

    // Format the metadata
    const formattedMetadataNestedArr = metadataNestedArr.map((metadataArr) =>
      formatDatastreamMetadataForChart(metadataArr)
    );

    // Extract the formatted metadata properties
    const extractedFormattedDatastreamProperties =
      extractPropertiesFromFormattedDatastreamMetadata(
        formattedMetadataNestedArr,
        false
      );

    drawColumnChartHighcharts(
      formattedObservationsNestedArr,
      extractedFormattedDatastreamProperties
    );
  } catch (err) {
    console.error(err);
  }
};

/**
 * Test drawing of line chart using aggregation / average result - monthly
 */
const drawLineChartMonthlyAverageTest = async function () {
  try {
    const sensorsOfInterestNestedArr = [
      ["125", "vl", "60min"],
      ["225", "vl", "60min"],
    ];

    const observationsPlusMetadata =
      await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
        BASE_URL,
        QUERY_PARAMS_COMBINED,
        sensorsOfInterestNestedArr
      );

    // Extract the observations and metadata for each sensor
    // Array elements in same order as input array
    const [obsNestedArr, metadataNestedArr] = observationsPlusMetadata;

    // User-specified start date and end date
    const startDate = "2020-02-01";
    const endDate = "2020-05-31";

    // Extract observations within the user-specified start and end date
    const observationsNestedArr = obsNestedArr.map((obsArr) =>
      extractObservationsWithinDatesInterval(
        obsArr,
        "60min",
        startDate,
        endDate
      )
    );

    // Unique calendar dates
    const uniqueCalendarDatesNestedArr = observationsNestedArr.map(
      (observationsArr) =>
        extractUniqueCalendarDatesFromTimestamp(observationsArr)
    );

    // Unique calendar months
    const uniqueCalendarMonthsNestedArr = uniqueCalendarDatesNestedArr.map(
      (uniqueCalendarDatesArr) =>
        extractUniqueCalendarMonthsFromCalendarDates(uniqueCalendarDatesArr)
    );

    // Calculate average of values of observations - monthly
    const observationsAverageMonthlyNestedArr =
      calculateAverageOfObservationValuesWithinInterval(
        observationsNestedArr,
        "60min",
        uniqueCalendarMonthsNestedArr,
        "monthly"
      );

    // Format the observations
    const formattedObservationsAverageMonthlyNestedArr =
      observationsAverageMonthlyNestedArr.map((obsAverageMonthlyArr, i) =>
        formatAggregationResultForColumnChart(
          uniqueCalendarMonthsNestedArr[i],
          obsAverageMonthlyArr
        )
      );

    // Format the metadata
    const formattedMetadataNestedArr = metadataNestedArr.map((metadataObj) =>
      formatDatastreamMetadataForChart(metadataObj)
    );

    // Extract the formatted metadata properties
    const extractedFormattedDatastreamProperties =
      extractPropertiesFromFormattedDatastreamMetadata(
        formattedMetadataNestedArr,
        true,
        "monthly",
        "average"
      );

    drawLineChartHighcharts(
      formattedObservationsAverageMonthlyNestedArr,
      extractedFormattedDatastreamProperties
    );
  } catch (err) {
    console.error(err);
  }
};

/**
 * Test drawing of line chart using aggregation / average result - daily
 */
const drawLineChartDailyAverageTest = async function () {
  try {
    const sensorsOfInterestNestedArr = [
      ["125", "vl", "60min"],
      ["225", "vl", "60min"],
    ];

    const observationsPlusMetadata =
      await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
        BASE_URL,
        QUERY_PARAMS_COMBINED,
        sensorsOfInterestNestedArr
      );

    // Extract the observations and metadata for each sensor
    // Array elements in same order as input array
    const [obsNestedArr, metadataNestedArr] = observationsPlusMetadata;

    // User-specified start date and end date
    const startDate = "2020-02-01";
    const endDate = "2020-05-31";

    // Extract observations within the user-specified start and end date
    const observationsNestedArr = obsNestedArr.map((obsArr) =>
      extractObservationsWithinDatesInterval(
        obsArr,
        "60min",
        startDate,
        endDate
      )
    );

    // Unique calendar dates
    const uniqueCalendarDatesNestedArr = observationsNestedArr.map(
      (observationsArr) =>
        extractUniqueCalendarDatesFromTimestamp(observationsArr)
    );

    // Calculate average of values of observations - daily
    const observationsAverageDailyNestedArr =
      calculateAverageOfObservationValuesWithinInterval(
        observationsNestedArr,
        "60min",
        uniqueCalendarDatesNestedArr,
        "daily"
      );

    // Format the observations - daily
    const formattedObservationsAverageDailyNestedArr =
      observationsAverageDailyNestedArr.map((obsAverageDailyArr, i) =>
        formatAggregationResultForColumnChart(
          uniqueCalendarDatesNestedArr[i],
          obsAverageDailyArr
        )
      );

    // Format the metadata
    const formattedMetadataNestedArr = metadataNestedArr.map((metadataObj) =>
      formatDatastreamMetadataForChart(metadataObj)
    );

    // Extract the formatted metadata properties
    const extractedFormattedDatastreamProperties =
      extractPropertiesFromFormattedDatastreamMetadata(
        formattedMetadataNestedArr,
        true,
        "daily",
        "average"
      );

    drawLineChartHighcharts(
      formattedObservationsAverageDailyNestedArr,
      extractedFormattedDatastreamProperties
    );
  } catch (err) {
    console.error(err);
  }
};

// drawScatterPlotHCTest2();
// drawHeatmapHCUsingTempDifference();
// testLineChartMultipleSeries();
// drawColumnChartMonthlySumTest();
// drawColumnChartDailySumTest();
// drawColumnChartNonAggregationTest();
// drawLineChartMonthlyAverageTest();
// drawLineChartDailyAverageTest();
