"use strict";

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

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

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

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

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

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

import {
  showLoadingSpinner,
  hideLoadingSpinner,
} from "./src_modules/loadingIndicator.mjs";

import { vanillaSelectBox } from "./thirdparty/vanillaSelectBox.mjs";

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

import {
  splitMultipleOptionsTextDelimitedBySlash,
  getSelectedOptionsFromAllDropDownLists,
  checkIfSelectedOptionsContainTemperatureDifference,
  deleteTemperatureDifferenceOptions,
  extractTemperatureDifferenceOptions,
  extractBuildingPlusSamplingRate,
  checkIfChartRequiresRawObservations,
  getAbbreviationsForSelectedOptionsFromAllDropDownLists,
} from "./src_modules/dropDownListHelpers.mjs";

import {
  drawHeatmapBasedOnSelectedOptions,
  drawScatterPlotFromChartSelection,
  drawLineChartBasedOnSelectedAggregationOptions,
  drawColumnChartBasedOnSelectedAggregationOptions,
} from "./src_modules/dropDownListProcessing.mjs";

/**
 * Use the `vanillaDropDown` library to style the buildings & data points drop down list
 *
 * @returns {undefined}
 */
const styleBuildingsDataPointsDropDown = function () {
  // Create our dropdown list using `vanillaSelectBox`; supports the selection of multiple options
  new vanillaSelectBox("#drop-down--bldg-data-point", {
    "disableSelectAll": true,
    "maxSelect": 5,
    "placeHolder": "--Select--",
    "search": false,
  });
};

/**
 * Use the `vanillaDropDown` library to style the aggregation type drop down list
 *
 * @returns {undefined}
 */
const styleAggregationDropDown = function () {
  // Create our dropdown list using `vanillaSelectBox`
  new vanillaSelectBox("#drop-down--aggregation-type", {
    "disableSelectAll": true,
    "maxSelect": 1,
    "placeHolder": "--Select--",
    "search": false,
  });
};

/**
 * Use the `vanillaDropDown` library to style the third sampling rate down list
 *
 * @returns {undefined}
 */
const styleSamplingRateDropDown = function () {
  // Create our dropdown list using `vanillaSelectBox`
  new vanillaSelectBox("#drop-down--sampling-rate", {
    "disableSelectAll": true,
    "maxSelect": 1,
    "placeHolder": "--Select--",
    "search": false,
  });
};

/**
 * Use the `vanillaDropDown` library to style the chart type drop down list
 *
 * @returns {undefined}
 */
const styleChartTypeDropDown = function () {
  // Create our dropdown list using `vanillaSelectBox`
  new vanillaSelectBox("#drop-down--chart-type", {
    "disableSelectAll": true,
    "maxSelect": 1,
    "placeHolder": "--Select--",
    "search": false,
  });
};

/**
 * Callback function that wraps the logic of populating the linked drop down lists.
 * Will run on `DOMContentLoaded` event
 *
 * @returns {undefined}
 */
const afterDocumentLoads = function () {
  styleBuildingsDataPointsDropDown();
  styleAggregationDropDown();
  styleSamplingRateDropDown();
  styleChartTypeDropDown();
};

/**
 * Callback function that draws a chart using options from the drop-down list that
 * have been selected by a user.
 * Will be run when the user clicks a button
 *
 * @async
 * @returns {undefined} undefined
 */
const drawChartUsingSelectedOptions = async function () {
  try {
    const selectedOptionsAllDropDownLists =
      getSelectedOptionsFromAllDropDownLists();

    // Note: The aggregation type + duration and chart type are the second and
    // fourth elements respectively, we have ignored the first and third elements
    const [, selectedAggregationTypeDurationArr, , selectedChartTypeArr] =
      selectedOptionsAllDropDownLists;

    // Create an array of aggregation type and duration
    const selectedAggregationTypeDurationSplitNestedArr =
      splitMultipleOptionsTextDelimitedBySlash(
        selectedAggregationTypeDurationArr
      );

    // Separate the aggregation type and the aggregation duration strings
    const [selectedAggregationTypeDurationSplitArr] =
      selectedAggregationTypeDurationSplitNestedArr;

    const [selectedAggregationTypeArr, selectedAggregationDuration] =
      selectedAggregationTypeDurationSplitArr;

    // Array of building(s) + data point(s) + sampling rate
    const selectedBuildingsDataPointsSamplingRateAbbrev =
      getAbbreviationsForSelectedOptionsFromAllDropDownLists(
        selectedOptionsAllDropDownLists
      );

    // Create copies of the arrays of building(s) + data point(s) + sampling rate
    const selectedBuildingsDataPointsSamplingRateAbbrevNonComputedCopy = [
      ...selectedBuildingsDataPointsSamplingRateAbbrev,
    ];

    const selectedBuildingsDataPointsSamplingRateAbbrevComputedCopy = [
      ...selectedBuildingsDataPointsSamplingRateAbbrev,
    ];

    // Check if we have non-computed
    const selectedBuildingsDataPointsSamplingRateAbbrevNonComputed =
      checkIfSelectedOptionsContainTemperatureDifference(
        selectedBuildingsDataPointsSamplingRateAbbrevNonComputedCopy
      )
        ? deleteTemperatureDifferenceOptions(
            selectedBuildingsDataPointsSamplingRateAbbrevNonComputedCopy
          )
        : selectedBuildingsDataPointsSamplingRateAbbrevNonComputedCopy;

    // Check if we have computed / dT
    const selectedBuildingsDataPointsSamplingRateAbbrevComputed =
      checkIfSelectedOptionsContainTemperatureDifference(
        selectedBuildingsDataPointsSamplingRateAbbrevComputedCopy
      )
        ? extractTemperatureDifferenceOptions(
            selectedBuildingsDataPointsSamplingRateAbbrevComputedCopy
          )
        : [];

    // Display the loading indicator
    showLoadingSpinner();

    // Fetch the observations + metadata / non-computed
    const observationsPlusMetadataNonComputed =
      selectedBuildingsDataPointsSamplingRateAbbrevNonComputed.length === 0
        ? [[], []]
        : await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
            BASE_URL,
            QUERY_PARAMS_COMBINED,
            selectedBuildingsDataPointsSamplingRateAbbrevNonComputed
          );

    // Fetch the observations + metadata / computed (dT)
    const observationsPlusMetadataComputed =
      selectedBuildingsDataPointsSamplingRateAbbrevComputed.length === 0
        ? [[], []]
        : await calculateVorlaufMinusRuecklaufTemperature(
            BASE_URL,
            QUERY_PARAMS_COMBINED,
            extractBuildingPlusSamplingRate(
              selectedBuildingsDataPointsSamplingRateAbbrevComputed
            )
          );

    // Extract the combined arrays for observations and metadata / non-computed
    const [observationsNestedNonComputedArr, metadataNestedNonComputedArr] =
      observationsPlusMetadataNonComputed;

    // Extract the combined arrays for observations and metadata / computed (dT)
    const [observationsNestedComputedArr, metadataNestedComputedArr] =
      observationsPlusMetadataComputed;

    // Create a combined array of observations and metadata
    const observationsPlusMetadataCombined = [
      [...observationsNestedNonComputedArr, ...observationsNestedComputedArr],
      [...metadataNestedNonComputedArr, ...metadataNestedComputedArr],
    ];

    const [observationsComboNestedArr, metadataComboNestedArr] =
      observationsPlusMetadataCombined;

    // Create formatted array(s) for metadata - used by ALL chart types
    const formattedMetadataNestedArr = metadataComboNestedArr.map(
      (metadataObj) => formatDatastreamMetadataForChart(metadataObj)
    );

    // Extract the formatted metadata properties - used by ALL chart types
    const extractedFormattedDatastreamProperties =
      extractPropertiesFromFormattedDatastreamMetadata(
        formattedMetadataNestedArr,
        false
      );

    // The formatted abbreviations array is nested
    const [selectedBuildingsDataPointsSamplingRateAbbrevArr] =
      selectedBuildingsDataPointsSamplingRateAbbrev;

    // Extract the formatted sampling rate string - used by ALL chart types
    const [, , selectedSamplingRateAbbrev] =
      selectedBuildingsDataPointsSamplingRateAbbrevArr;

    // User-specified start date and end date for aggregation - used by MULTIPLE chart types
    const aggregationStartDate = "2020-01-01";
    const aggregationEndDate = "2020-12-31";

    // Extract observations within the user-specified start and end date - used by MULTIPLE chart types
    const observationsAggregationNestedArr = observationsComboNestedArr.map(
      (obsArr) =>
        extractObservationsWithinDatesInterval(
          obsArr,
          "60min",
          aggregationStartDate,
          aggregationEndDate
        )
    );

    // Unique calendar dates - used by MULTIPLE chart types
    const uniqueCalendarDatesNestedArr = observationsAggregationNestedArr.map(
      (observationsArr) =>
        extractUniqueCalendarDatesFromTimestamp(observationsArr)
    );

    selectedChartTypeArr.forEach((selectedChartType) => {
      if (selectedChartType === "Heatmap") {
        // We are interested in raw observations
        if (
          checkIfChartRequiresRawObservations(
            selectedAggregationTypeArr,
            selectedAggregationDuration
          )
        ) {
          drawHeatmapBasedOnSelectedOptions(
            selectedBuildingsDataPointsSamplingRateAbbrev,
            observationsComboNestedArr,
            extractedFormattedDatastreamProperties
          );
        } else {
          throw new Error(
            "This type of chart (Heatmap) does not support aggregated results"
          );
        }
      }
      if (selectedChartType === "Scatter Plot") {
        // We are interested in raw observations
        if (
          checkIfChartRequiresRawObservations(
            selectedAggregationTypeArr,
            selectedAggregationDuration
          )
        ) {
          drawScatterPlotFromChartSelection(
            selectedBuildingsDataPointsSamplingRateAbbrev,
            observationsComboNestedArr,
            extractedFormattedDatastreamProperties
          );
        } else {
          throw new Error(
            "This type of chart (Scatter Plot) does not support aggregated results"
          );
        }
      }
      if (selectedChartType === "Line") {
        // We are interested in raw observations or aggregated observations

        // Raw observations
        if (selectedAggregationTypeArr === "None (raw data)") {
          // Create formatted array(s) for observations
          const formattedRawObservationsLineChartNestedArr =
            observationsComboNestedArr.map((observationsArr) =>
              formatSensorThingsApiResponseForLineOrColumnChart(observationsArr)
            );

          drawLineChartHighcharts(
            formattedRawObservationsLineChartNestedArr,
            extractedFormattedDatastreamProperties
          );
        }
        // Aggregated observations
        else {
          drawLineChartBasedOnSelectedAggregationOptions(
            selectedAggregationTypeArr,
            selectedAggregationDuration,
            observationsAggregationNestedArr,
            selectedSamplingRateAbbrev,
            uniqueCalendarDatesNestedArr,
            formattedMetadataNestedArr
          );
        }
      }
      if (selectedChartType === "Column") {
        // We are interested in raw observations or aggregated observations

        // Raw observations
        if (selectedAggregationTypeArr === "None (raw data)") {
          // Create formatted array(s) for observations
          const formattedRawObservationsColumnChartNestedArr =
            observationsComboNestedArr.map((observationsArr) =>
              formatSensorThingsApiResponseForLineOrColumnChart(observationsArr)
            );

          drawColumnChartHighcharts(
            formattedRawObservationsColumnChartNestedArr,
            extractedFormattedDatastreamProperties
          );
        }
        // Aggregated observations
        else {
          drawColumnChartBasedOnSelectedAggregationOptions(
            selectedAggregationTypeArr,
            selectedAggregationDuration,
            observationsAggregationNestedArr,
            selectedSamplingRateAbbrev,
            uniqueCalendarDatesNestedArr,
            formattedMetadataNestedArr
          );
        }
      }
    });
  } catch (err) {
    console.error(err);
  } finally {
    // Hide the loading indicator
    hideLoadingSpinner();
  }
};

document.addEventListener("DOMContentLoaded", afterDocumentLoads);

document
  .querySelector("#btn-draw-chart")
  .addEventListener("click", drawChartUsingSelectedOptions);
