"use strict";

// Request parameters
const BASE_URL =
  "http://193.196.39.91:8080/frost-icity-tp31/v1.1/Datastreams(80)/Observations";
const BASE_URL2 =
  "http://193.196.39.91:8080/frost-icity-tp31-v2/v1.1/Datastreams(41)/Observations";
const PARAM_RESULT_FORMAT = "dataArray";
const PARAM_ORDER_BY = "phenomenonTime asc";
const PARAM_FILTER =
  "resultTime ge 2020-01-01T00:00:00.000Z and resultTime le 2020-07-01T00:00:00.000Z";
const PARAM_SELECT = "result,phenomenonTime";

/**
 * Draw an EMPTY chart using Apexcharts library
 * @param {HTMLElement} htmlElement - HTML element where chart will be drawn
 * @param {String} mainTitle - Main chart title
 * @param {String} yAxisTitle - Y-axis title
 * @returns {Object} - An empty chart object
 */
const drawEmptyLineChartAC = function (
  htmlElement,
  mainTitle = "Main Chart Title",
  yAxisTitle = "y-axis title"
) {
  // Chart constants
  const CHART_HTML_ELEMENT = htmlElement;
  const TITLE_TEXT = mainTitle;
  const Y_AXIS_TITLE = yAxisTitle;

  const options = {
    series: [],
    chart: {
      type: "area",
      stacked: false,
      height: 350,
      zoom: {
        type: "x",
        enabled: true,
        autoScaleYaxis: true,
      },
      toolbar: {
        autoSelected: "zoom",
      },
    },
    dataLabels: {
      enabled: false,
    },
    markers: {
      size: 0,
    },
    title: {
      text: TITLE_TEXT,
      align: "left",
    },
    noData: {
      text: "Loading...",
    },
    fill: {
      type: "gradient",
      gradient: {
        shadeIntensity: 1,
        inverseColors: false,
        opacityFrom: 0.5,
        opacityTo: 0,
        stops: [0, 90, 100],
      },
    },
    yaxis: {
      labels: {
        formatter: function (val) {
          return val.toFixed(0);
        },
        forceNiceScale: true,
      },
      title: {
        text: Y_AXIS_TITLE,
      },
    },
    xaxis: {
      type: "datetime",
    },
    tooltip: {
      shared: false,
      y: {
        formatter: function (val) {
          return val.toFixed(2);
        },
      },
    },
  };

  const chart = new ApexCharts(CHART_HTML_ELEMENT, options);
  return chart;
};

// Line chart 1 constants
const chart1LineHTML = document.querySelector("#chart-apex-line");
const chart1LineTitle = "Inlet flow (Vorlauf)";
const chart1LineYAxisTitle = "Temperature (°C)";

// Draw an empty line chart
const lineChartApex = drawEmptyLineChartAC(
  chart1LineHTML,
  chart1LineTitle,
  chart1LineYAxisTitle
);
lineChartApex.render();

/**
 * Update an empty chart created using Apexcharts library
 * @param {String} chartName
 * @param {Array} dataArr
 * @returns {void}
 */
const updateLineChartAC = function (chartName, dataArr) {
  const CHART_NAME = chartName;
  // Update the chart
  lineChartApex.updateSeries([
    {
      name: CHART_NAME,
      data: dataArr,
    },
  ]);
};

/**
 * Draw a heatmap using the ApexCharts library
 * ATTEMPT 1
 * @param {Array} obsArray - Response from SensorThings API as array
 * @returns {void}
 */
const drawHeatMapAC1 = function (obsArray) {
  // Chart constants
  const CHART_HEATMAP_TITLE = "HeatMap Chart";
  const CHART_HEATMAP_NAME_SERIES_1 = "VL-225";
  // const CHART_HEATMAP_NAME_SERIES_2 = "W2";

  /**
   * Convert SensorThings API response (an array) into an object
   * @returns {Object} - Chart series object
   */
  const generateHeatMapData = function () {
    const series = [];
    obsArray.forEach(([obsTime, obsValue]) => {
      series.push({
        x: obsTime.slice(0, -1), // remove trailing "Z" from timestamp
        y: obsValue,
      });
    });
    return series;
  };

  const data = [
    {
      name: CHART_HEATMAP_NAME_SERIES_1,
      data: generateHeatMapData(obsArray),
    },
    // {
    //   name: CHART_HEATMAP_NAME_SERIES_2,
    //   data: generateHeatMapData(obsArray),
    // },
  ];

  data.reverse();

  const colors = [
    "#F3B415",
    "#F27036",
    "#663F59",
    "#6A6E94",
    "#4E88B4",
    "#00A7C6",
    "#18D8D8",
    "#A9D794",
    "#46AF78",
    "#A93F55",
    "#8C5E58",
    "#2176FF",
    "#33A1FD",
    "#7A918D",
    "#BAFF29",
  ];

  // colors.reverse();

  const options = {
    series: data,
    chart: {
      height: 350,
      type: "heatmap",
    },
    dataLabels: {
      enabled: false,
    },
    colors: colors,

    title: {
      text: CHART_HEATMAP_TITLE,
    },
    grid: {
      padding: {
        right: 20,
      },
    },
    xaxis: {
      type: "datetime",
    },
    tooltip: {
      shared: false,
      x: {
        formatter: function (val) {
          return new Date(val).toLocaleString();
        },
      },
      y: {
        formatter: function (val) {
          return val.toFixed(2);
        },
      },
    },
    plotOptions: {
      heatmap: {
        useFillColorAsStroke: true, // we need this option for the chart to be visible
        // distributed: true,
        // enableShades: false,
      },
    },
  };

  const chart = new ApexCharts(
    document.querySelector("#chart-apex-heatmap"),
    options
  );
  chart.render();
};

/**
 * Draw a heatmap using the ApexCharts library
 * ATTEMPT 2
 * @param {Array} obsArray - Response from SensorThings API as array
 * @returns {void}
 */
const drawHeatMapAC2 = function (obsArray) {
  // Chart constants
  const CHART_HEATMAP_TITLE = "HeatMap Chart";
  const CHART_HEATMAP_NAME_SERIES_1 = "VL-225";

  /**
   * Convert SensorThings API response (an array) into an object
   * @returns {Object} - Chart series object
   */
  const generateHeatMapData = function () {
    const series = [];
    obsArray.forEach(([obsTime, obsValue]) => {
      series.push({
        x: obsTime.slice(0, -1), // remove trailing "Z" from timestamp
        y: obsValue,
      });
    });
    return series;
  };

  const data = [
    {
      name: CHART_HEATMAP_NAME_SERIES_1,
      data: generateHeatMapData(obsArray),
    },
    // {
    //   name: CHART_HEATMAP_NAME_SERIES_2,
    //   data: generateHeatMapData(obsArray),
    // },
  ];

  // Constants for our data range
  const LOW_FROM = 65;
  const LOW_TO = 70;
  const MEDIUM_FROM = 70;
  const MEDIUM_TO = 75;
  const HIGH_FROM = 75;
  const HIGH_TO = 80;
  const EXTREME_FROM = 80;
  const EXTREME_TO = 85;
  const options = {
    series: data,
    chart: {
      height: 450,
      type: "heatmap",
    },
    plotOptions: {
      heatmap: {
        shadeIntensity: 0.5,
        radius: 0,
        useFillColorAsStroke: true,
        colorScale: {
          ranges: [
            {
              from: null,
              to: null,
              name: "null",
              color: "#525252",
            },
            {
              from: LOW_FROM,
              to: LOW_TO,
              name: `${LOW_FROM}°C`,
              color: "#1a9641",
            },
            {
              from: MEDIUM_FROM,
              to: MEDIUM_TO,
              name: `${MEDIUM_FROM}°C`,
              color: "#a6d96a",
            },
            {
              from: HIGH_FROM,
              to: HIGH_TO,
              name: `${HIGH_FROM}°C`,
              color: "#fdae61",
            },
            {
              from: EXTREME_FROM,
              to: EXTREME_TO,
              name: `${EXTREME_FROM}°C`,
              color: "#d7191c",
            },
          ],
        },
      },
    },
    dataLabels: {
      enabled: false,
    },
    stroke: {
      width: 1,
    },
    title: {
      text: CHART_HEATMAP_TITLE,
    },
    grid: {
      padding: {
        right: 20,
      },
    },
    xaxis: {
      type: "datetime",
      // labels: {
      //   format: "MMM",
      // },
    },
    tooltip: {
      shared: false,
      x: {
        formatter: function (val) {
          return new Date(val).toLocaleString();
        },
      },
      y: {
        formatter: function (val) {
          if (val) {
            return val.toFixed(2);
          } else {
            return "null";
          }
        },
      },
    },
    // distributed: true,
  };

  const chart = new ApexCharts(
    document.querySelector("#chart-apex-heatmap"),
    options
  );
  chart.render();
};

/**
 * Follows "@iot.nextLink" links in SensorThingsAPI's response
 * Appends new results to existing results
 * @async
 * @param {Object} responsePromise - Promise object
 * @returns {Object} - Object containing results from all the "@iot.nextLink" links
 */
const followNextLink = function (responsePromise) {
  return responsePromise
    .then(function (lastSuccess) {
      if (lastSuccess.data["@iot.nextLink"]) {
        return followNextLink(
          axios.get(lastSuccess.data["@iot.nextLink"])
        ).then(function (nextLinkSuccess) {
          nextLinkSuccess.data.value = lastSuccess.data.value.concat(
            nextLinkSuccess.data.value
          );
          return nextLinkSuccess;
        });
      } else {
        return lastSuccess;
      }
    })
    .catch(function (err) {
      console.log(err);
    });
};

///////////////////////////////////////////////////////////////
function getDataReadyForSimplifyJS(pts) {
  var val = [];
  
  for (var i = 0, len = pts.length; i < len; i++) 
    val.push(pts[i][1]);
  
  pts = val;

  let newPts = [];
  for (var i = 0, len = pts.length; i < len; i++) 
    newPts.push({ x: i, y: pts[i] });  
  return newPts;
}
///////////////////////////////////////////////////////////////
function getPointIndiciesFromXYjson(pts) {
  let newPts = [];
  for (var i = 0, len = pts.length; i < len; i++) 
    newPts.push(pts[i].x);    
  return newPts;
}

///////////////////////////////////////////////////////////////
function getReducedDataFromSimplifiedData(originalData, simplified_data) {    
  let red_data = [];
  let new_start = 0;
  for (var i = 0; i < originalData.length; i++) 
    for (var j=new_start; j < simplified_data.length; j++){
      if (i == simplified_data[j].x){
        red_data.push([originalData[i][0],originalData[i][1]]);
        new_start = j+1;
      }
    }
  return red_data;
}

// Get "ALL" the Observations that satisfy our query
var res = followNextLink(
  axios.get(BASE_URL, {
    params: {
      "$resultFormat": PARAM_RESULT_FORMAT,
      "$orderBy": PARAM_ORDER_BY,
      "$filter": PARAM_FILTER,
      "$select": PARAM_SELECT,
    },
  })
)
  .then((success) => {
    const successValue = success.data.value;

    // Array that will hold the combined observations
    const combinedObservations = [];

    successValue.forEach((dataObj) => {
      // Each page of results will have a dataArray that holds the observations
      const dataArrays = dataObj.dataArray;

      combinedObservations.push(...dataArrays);
    });
    // DEBUG: Check total number of observations
    console.log(combinedObservations.length);
    // DEBUG: Print the array of observations
    console.log(combinedObservations);

    return combinedObservations;
  })
  .catch((err) => {
    console.log(err);
  })
  .then((observationArr) => {
    // updateLineChartAC(chart1LineTitle, observationArr);
     
    let simplified_data = simplify(getDataReadyForSimplifyJS(observationArr),2,true);
    let reducedData =  getReducedDataFromSimplifiedData(observationArr, simplified_data);

    updateLineChartAC(chart1LineTitle, reducedData);
    // drawHeatMapAC2(observationArr);
    drawHeatMapAC2(reducedData);
    console.log(reducedData.length, observationArr.length);
    return reducedData;
  });

