"use strict";

// DEBUG:
// Observations WITHOUT data gap - Bau 225 / Datastream ID = 80
// Observations WITH data gap - Bau 112 / Datastream ID = 78

export const BASE_URL = "http://193.196.39.91:8080/frost-icity-tp31/v1.1";

/**
 * Retrieve the datastream ID that corresponds to a particular building
 * @param {*} buildingNumber Integer representing the building ID
 * @param {*} phenomenon String representing the phenomenon of interest
 * @param {*} samplingRate String representing the sampling rate of the observations
 * @returns {Number} Datastream corresponding to the input building
 */
export const getDatastreamIdFromBuildingNumber = function(
    buildingNumber,
    phenomenon,
    samplingRate
) {
    const buildingToDatastreamMapping = {
        101: {
            vl: { "15min": "69", "60min": "75" },
            rl: { "15min": "81", "60min": "87" },
            flow: { "15min": "93", "60min": "99" },
            power: { "15min": "105", "60min": "111" },
            energy: { "15min": "117", "60min": "123" },
            energy_verb: { "15min": "129", "60min": "135" },
        },
        102: {
            vl: { "15min": "70", "60min": "76" },
            rl: { "15min": "82", "60min": "88" },
            flow: { "15min": "94", "60min": "100" },
            power: { "15min": "106", "60min": "112" },
            energy: { "15min": "118", "60min": "124" },
            energy_verb: { "15min": "130", "60min": "136" },
        },
        107: {
            vl: { "15min": "71", "60min": "77" },
            rl: { "15min": "83", "60min": "89" },
            flow: { "15min": "95", "60min": "101" },
            power: { "15min": "107", "60min": "113" },
            energy: { "15min": "119", "60min": "125" },
            energy_verb: { "15min": "131", "60min": "137" },
        },
        "112, 118": {
            vl: { "15min": "72", "60min": "78" },
            rl: { "15min": "84", "60min": "90" },
            flow: { "15min": "96", "60min": "102" },
            power: { "15min": "108", "60min": "114" },
            energy: { "15min": "120", "60min": "126" },
            energy_verb: { "15min": "132", "60min": "138" },
        },
        125: {
            vl: { "15min": "73", "60min": "79" },
            rl: { "15min": "85", "60min": "91" },
            flow: { "15min": "97", "60min": "103" },
            power: { "15min": "109", "60min": "115" },
            energy: { "15min": "121", "60min": "127" },
            energy_verb: { "15min": "133", "60min": "139" },
        },
        225: {
            vl: { "15min": "74", "60min": "80" },
            rl: { "15min": "86", "60min": "92" },
            flow: { "15min": "98", "60min": "104" },
            power: { "15min": "110", "60min": "116" },
            energy: { "15min": "122", "60min": "128" },
            energy_verb: { "15min": "134", "60min": "140" },
        },
    };

    if (!buildingNumber) return;

    // check if building is contained in mapping object
    if (!(buildingNumber in buildingToDatastreamMapping)) return;

    const datastreamIdMatched = Number(
        buildingToDatastreamMapping[buildingNumber][phenomenon][samplingRate]
    );

    return datastreamIdMatched;
};

/**
 * Create URL to fetch the Observations corresponding to a provided Datastream
 * @param {Number} datastreamID - Integer representing the Datastream ID
 * @returns {String} URL string for fetching the Observations corresponding to a Datastream
 */
export const getObservationsUrl = function(baseUrl, datastreamID) {
    if (!datastreamID) return;
    const fullDatastreamURL = `${baseUrl}/Datastreams(${datastreamID})/Observations`;
    return fullDatastreamURL;
};

/**
 * Create a temporal filter string for the fetched Observations
 * @param {String} dateStart Start date in YYYY-MM-DD format
 * @param {String} dateStop Stop date in YYYY-MM-DD format
 * @returns {String} Temporal filter string
 */
export const createTemporalFilterString = function(dateStart, dateStop) {
    if (!dateStart || !dateStop) return;
    const filterString = `resultTime ge ${dateStart}T00:00:00.000Z and resultTime le ${dateStop}T00:00:00.000Z`;
    return filterString;
};

// const BASE_URL_OBSERVATIONS = getObservationsUrl(80);
export const PARAM_RESULT_FORMAT = "dataArray";
export const PARAM_ORDER_BY = "phenomenonTime asc";
// const PARAM_FILTER = createTemporalFilterString("2020-01-01", "2021-01-01");
export const PARAM_SELECT = "result,phenomenonTime";

// const axiosGetRequest = axios.get(BASE_URL_OBSERVATIONS, {
//   params: {
//     "$resultFormat": PARAM_RESULT_FORMAT,
//     "$orderBy": PARAM_ORDER_BY,
//     "$filter": PARAM_FILTER,
//     "$select": PARAM_SELECT,
//   },
// });



/**
 * Format the response from SensorThings API to make it suitable for heatmap
 * @param {Array} obsArray Response from SensorThings API as array
 * @returns {Array} Array of formatted observations suitable for use in a heatmap
 */
export const formatSTAResponseForHeatMap = function(obsArray) {
    if (!obsArray) return;
    const dataSTAFormatted = [];
    obsArray.forEach((obs) => {
        // Get the date/time string; first element in input array; remove trailing "Z"
        const obsDateTimeInput = obs[0].slice(0, -1);
        // Get the "date" part of an observation
        const obsDateInput = obs[0].slice(0, 10);
        // Create Date objects
        const obsDateTime = new Date(obsDateTimeInput);
        const obsDate = new Date(obsDateInput);
        // x-axis -> timestamp; will be the same for observations from the same date
        const timestamp = Date.parse(obsDate);
        // y-axis -> hourOfDay
        const hourOfDay = obsDateTime.getHours();
        // value -> the observation's value; second element in input array
        const value = obs[1];
        dataSTAFormatted.push([timestamp, hourOfDay, value]);
    });
    return dataSTAFormatted;
};

/**
 * Draw a heatmap using Highcharts library
 * @param {Array} formattedObsArrayForHeatmap Response from SensorThings API formatted for use in a heatmap
 * @returns {Object} Highcharts library heatmap object
 */
export const drawHeatMapHC = function(formattedObsArrayForHeatmap) {
    Highcharts.chart("chart-heatmap", {
        chart: {
            type: "heatmap",
            zoomType: "x",
        },

        boost: {
            useGPUTranslations: true,
        },

        title: {
            text: "Inlet flow (Vorlauf)",
            align: "left",
            x: 40,
        },

        subtitle: {
            text: "Temperature variation by day and hour in 2020",
            align: "left",
            x: 40,
        },

        xAxis: {
            type: "datetime",
            // min: Date.UTC(2017, 0, 1),
            // max: Date.UTC(2017, 11, 31, 23, 59, 59),
            labels: {
                align: "left",
                x: 5,
                y: 14,
                format: "{value:%B}", // long month
            },
            showLastLabel: false,
            tickLength: 16,
        },

        yAxis: {
            title: {
                text: null,
            },
            labels: {
                format: "{value}:00",
            },
            minPadding: 0,
            maxPadding: 0,
            startOnTick: false,
            endOnTick: false,
            // tickPositions: [0, 6, 12, 18, 24],
            tickPositions: [0, 3, 6, 9, 12, 15, 18, 21, 24],
            tickWidth: 1,
            min: 0,
            max: 23,
            reversed: true,
        },

        colorAxis: {
            stops: [
                [0, "#3060cf"],
                [0.5, "#fffbbc"],
                [0.9, "#c4463a"],
                [1, "#c4463a"],
            ],
            min: 60,
            max: 85,
            startOnTick: false,
            endOnTick: false,
            labels: {
                format: "{value}℃",
            },
        },

        series: [{
            data: formattedObsArrayForHeatmap,
            boostThreshold: 100,
            borderWidth: 0,
            nullColor: "#525252",
            colsize: 24 * 36e5, // one day
            tooltip: {
                headerFormat: "Temperature<br/>",
                pointFormat: "{point.x:%e %b, %Y} {point.y}:00: <b>{point.value} ℃</b>",
            },
            turboThreshold: Number.MAX_VALUE, // #3404, remove after 4.0.5 release
        }, ],
    });
};

/**
 * Convert the observations' phenomenonTime from an ISO 8601 string to Unix epoch
 * @param {Array} obsArray Response from SensorThings API as array
 * @returns {Array} Array of formatted observations suitable for use in a line chart
 */
export const formatSTAResponseForLineChart = function(obsArray) {
    if (!obsArray) return;
    const dataSTAFormatted = [];
    obsArray.forEach((result) => {
        const timestampObs = new Date(result[0].slice(0, -1)).getTime(); // slice() removes trailing "Z" character in timestamp
        const valueObs = result[1];
        dataSTAFormatted.push([timestampObs, valueObs]);
    });
    return dataSTAFormatted;
};

/**
 * Draw a line chart using Highcharts library
 * @param {Array} formattedObsArrayForLineChart - Response from SensorThings API formatted for use in a line chart
 * @returns {Object} Highcharts library line chart object
 */
export const drawLineChartHC = function(formattedObsArrayForLineChart) {
    // Create the chart
    Highcharts.stockChart("chart-line", {
        chart: {
            zoomType: "x",
        },

        rangeSelector: {
            selected: 1,
        },

        title: {
            text: "Inlet flow (Vorlauf)",
            "align": "left",
        },

        subtitle: {
            text: "Temperature variation by hour in 2020",
            align: "left",
        },

        series: [{
            name: "AAPL",
            data: formattedObsArrayForLineChart,
            tooltip: {
                valueDecimals: 2,
            },
            turboThreshold: Number.MAX_VALUE, // #3404, remove after 4.0.5 release
        }, ],
    });
};

/**
 * 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
 */
export const followNextLink = function(responsePromise) {
    if (!responsePromise) return;
    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);
        });
};

// Get "ALL" the Observations that satisfy our query
// followNextLink(axiosGetRequest)
//   .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) => {
//     drawHeatMapHC(observationArr);
//     drawLineChartHC(observationArr);
//   });