"use strict";

import { SENSORTHINGS_API_BASE_URL } from "./config.mjs";

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

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

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

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

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

import { styleAllDropDownLists } from "./src_modules/dropDownListStyling.mjs";

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

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

import { drawColumnChartBasedOnSelectedOptions } from "./src_modules/dropDownListChartColumn.mjs";

import { drawHeatmapBasedOnSelectedOptions } from "./src_modules/dropDownListChartHeatmap.mjs";

import { drawLineChartBasedOnSelectedOptions } from "./src_modules/dropDownListChartLine.mjs";

import { drawScatterPlotBasedOnSelectedOptions } from "./src_modules/dropDownListChartScatterPlot.mjs";

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

/**
 * 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 {
    // Note: The chart type amd aggregation type + duration are the first and
    // third elements respectively, we have ignored the second and fourth elements
    const [selectedChartTypeArr, , selectedAggregationTypeDurationArr] =
      getSelectedOptionsFromAllDropDownLists();

    // Note: the resulting array is nested, it only has one sub-array
    // Separate the aggregation type and the aggregation duration strings
    const [[selectedAggregationType, selectedAggregationDuration]] =
      splitMultipleOptionsTextDelimitedBySlash(
        selectedAggregationTypeDurationArr
      );

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

    // The formatted abbreviations array is nested, we are interested in the first sub-array
    // We assume that all the phenomena have the same sampling rate
    // Extract the formatted sampling rate string - used by ALL chart types
    const [[, , selectedSamplingRateAbbrev]] =
      selectedBuildingsDataPointsSamplingRateAbbrevNestedArr;

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

    // The values of these references is either equal to `true` or an error will be thrown
    // We would like the errors to be thrown at this point before we begin performing any asynchronous tasks
    const selectedAggregationOptionsAreValid =
      checkIfSelectedAggregationOptionsAreValid(
        selectedChartTypeArr,
        selectedAggregationType,
        selectedAggregationDuration
      );

    const selectedBuildingDataPointsOptionsAreValid =
      checkIfSelectedBuildingDataPointsOptionsAreValid(
        selectedChartTypeArr,
        selectedBuildingsDataPointsSamplingRateAbbrevNestedArr
      );

    // Check whether we have dT (temperature difference), if so, delete these options,
    // then compute abbreviations for raw observations
    const selectedBuildingsDataPointsSamplingRateAbbrevRawObsArr =
      checkIfSelectedOptionsContainTemperatureDifference(
        selectedBuildingsDataPointsSamplingRateAbbrevNestedArr
      )
        ? deleteTemperatureDifferenceOptions(
            selectedBuildingsDataPointsSamplingRateAbbrevNestedArr
          )
        : selectedBuildingsDataPointsSamplingRateAbbrevNestedArr;

    // Check if we have dT (temperature difference), if so, extract these options
    const selectedBuildingsDataPointsSamplingRateAbbrevTempDiffArr =
      checkIfSelectedOptionsContainTemperatureDifference(
        selectedBuildingsDataPointsSamplingRateAbbrevNestedArr
      )
        ? extractTemperatureDifferenceOptions(
            selectedBuildingsDataPointsSamplingRateAbbrevNestedArr
          )
        : [];

    // Display the loading indicator
    showLoadingSpinner();

    // Disable the 'draw chart' button
    disableDrawChartButton();

    // Fetch and extract the observations + metadata / raw observations
    const [observationsRawNestedArr, metadataRawNestedArr] =
      selectedBuildingsDataPointsSamplingRateAbbrevRawObsArr.length === 0
        ? [[], []]
        : await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
            SENSORTHINGS_API_BASE_URL,
            QUERY_PARAMS_COMBINED,
            selectedBuildingsDataPointsSamplingRateAbbrevRawObsArr
          );

    // Fetch and extract the observations + metadata / temperature difference (dT)
    const [observationsTempDiffNestedArr, metadataTempDiffNestedArr] =
      selectedBuildingsDataPointsSamplingRateAbbrevTempDiffArr.length === 0
        ? [[], []]
        : await calculateVorlaufMinusRuecklaufTemperature(
            SENSORTHINGS_API_BASE_URL,
            QUERY_PARAMS_COMBINED,
            extractBuildingPlusSamplingRate(
              selectedBuildingsDataPointsSamplingRateAbbrevTempDiffArr
            )
          );

    // Create and extract the combined observations and metadata
    const [observationsCombinedNestedArr, metadataCombinedNestedArr] = [
      [...observationsRawNestedArr, ...observationsTempDiffNestedArr],
      [...metadataRawNestedArr, ...metadataTempDiffNestedArr],
    ];

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

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

    // Create final array of observations- used by MULTIPLE chart types
    // If we are performing aggregation, it was envisioned that the user would
    // select observations that fall within a start and end date
    const observationsComboNestedFinalArr =
      selectedAggregationType === "None (raw data)"
        ? observationsCombinedNestedArr
        : observationsCombinedNestedArr.map((observationsArr) =>
            extractObservationsWithinDatesInterval(
              observationsArr,
              selectedSamplingRateAbbrev,
              AGGREGATION_START_DATE,
              AGGREGATION_STOP_DATE
            )
          );

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

    for (const selectedChartType of selectedChartTypeArr) {
      switch (selectedChartType) {
        case "Heatmap":
          if (
            selectedAggregationOptionsAreValid &&
            selectedBuildingDataPointsOptionsAreValid
          ) {
            drawHeatmapBasedOnSelectedOptions(
              observationsComboNestedFinalArr,
              rawObsExtractedFormattedDatastreamProperties
            );
          }
          break;

        case "Scatter Plot":
          if (
            selectedAggregationOptionsAreValid &&
            selectedBuildingDataPointsOptionsAreValid
          ) {
            drawScatterPlotBasedOnSelectedOptions(
              observationsComboNestedFinalArr,
              rawObsExtractedFormattedDatastreamProperties
            );
          }
          break;

        case "Line":
          drawLineChartBasedOnSelectedOptions(
            selectedAggregationType,
            selectedAggregationDuration,
            observationsComboNestedFinalArr,
            selectedSamplingRateAbbrev,
            uniqueCalendarDatesNestedArr,
            formattedMetadataNestedArr
          );
          break;

        case "Column":
          drawColumnChartBasedOnSelectedOptions(
            selectedAggregationType,
            selectedAggregationDuration,
            observationsComboNestedFinalArr,
            selectedSamplingRateAbbrev,
            uniqueCalendarDatesNestedArr,
            formattedMetadataNestedArr
          );
          break;

        default:
          throw new Error("None of the chart type options were selected");
      }
    }
  } catch (err) {
    console.error(err);

    // Display a popup that displays the error message
    createErrorPopupMessage(err);
  } finally {
    // Enable the 'draw chart' button
    enableDrawChartButton();

    // Hide the loading indicator
    hideLoadingSpinner();
  }
};

document.addEventListener("DOMContentLoaded", afterDocumentLoads);

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