import './LineTemporalChart.component';
import { NAN_STRING } from '../constants';
//Given a field containing dots ".", vega is interpreting this as an accessor
//for nested objects, breaking then the internal mechnism to retrieve tooltip
//data from the mouse position. We are fixing it by replacing the dots by a
//well-known string that we expect no one would use to label a serie.
export function normlizeVegaFieldName(fieldName) {
    return fieldName.replace(/(\.)/g, 'VEGADOESNTSUPPORTDOTINFIELDNAME');
}
export function convert2VegaData(addedMissingDataPointSeries) {
    const flatArr = [];
    addedMissingDataPointSeries.forEach((line) => {
        line.data.forEach((datum) => {
            const obj = {
                timestamp: datum[0] * 1000,
                // convert to million second
                label: normlizeVegaFieldName(line.getTooltipLabel(line.metricPrefix, line.resource)),
                resource: line.resource,
                value: datum[1] && datum[1] !== NAN_STRING ? Number(datum[1]) : NAN_STRING,
                isNegativeValue: line.metricPrefix === 'read' || line.metricPrefix === 'out',
                isDashed: line.isLineDashed || false,
            };
            flatArr.push(obj);
        });
    });
    return flatArr;
}
// base on the current base value, convert the original vegadata to
export function convertDataBaseValue(data, base) {
    return data.map((datum) => {
        return {
            ...datum,
            value: typeof datum.value === 'number'
                ? getRelativeValue(datum.value, base)
                : NAN_STRING,
        };
    });
}
/**
 * Return the unit label base on the current dataset, and the valueBase which is used to convert the data
 * @param {any} unitRange
 * @param {any} maxValue the maximum value among the data set
 * @returns {any}
 */
export function getUnitLabel(unitRange, maxValue) {
    if (!unitRange || unitRange.length === 0) {
        return {
            valueBase: 1,
            unitLabel: '',
        };
    }
    // first sort the unitRange
    unitRange.sort((unitA, unitB) => {
        return unitA.threshold - unitB.threshold;
    });
    let index = unitRange.findIndex((range) => range.threshold > maxValue);
    // last unit
    if (index === -1) {
        index = unitRange.length;
    }
    if (index === 0) {
        return {
            valueBase: unitRange[index].threshold,
            unitLabel: unitRange[index].label,
        };
    }
    return {
        valueBase: unitRange[index - 1].threshold,
        unitLabel: unitRange[index - 1].label,
    };
}
/**
 * This function manually adds the missing data points with `null` value caused by downtime of the VMs
 * Missing data points are only added when the gap between consecutive data points is bigger than 2 intervals
 *
 * @param {array} orginalValues - The array of the data points are already sorted according to the time series
 * @param {number} startingTimeStamp - The starting timestamp in seconds
 * @param {number} sampleDuration - The time span value in seconds
 * @param {number} sampleInterval - The time difference between two data points in seconds
 *
 */
export function addMissingDataPoint(orginalValues, startingTimeStamp, sampleDuration, sampleInterval) {
    if (!orginalValues ||
        startingTimeStamp === undefined ||
        !sampleDuration ||
        !sampleInterval ||
        startingTimeStamp < 0 ||
        sampleDuration <= 0 ||
        sampleInterval <= 0) {
        return [];
    }
    // If there are no original values, return empty array
    if (orginalValues.length === 0) {
        return [];
    }
    const newValues = [];
    // add missing data points for the starting time
    for (let i = startingTimeStamp; i < orginalValues[0][0]; i += sampleInterval) {
        newValues.push([i, NAN_STRING]);
    }
    // Process all but the last element
    for (let i = 0; i < orginalValues.length - 1; i++) {
        if (orginalValues[i][0] < startingTimeStamp ||
            orginalValues[i][0] > startingTimeStamp + sampleDuration) {
            continue;
        }
        // Always add the current data point
        newValues.push(orginalValues[i]);
        const currentTimestamp = orginalValues[i][0];
        const nextTimestamp = orginalValues[i + 1][0];
        const gap = nextTimestamp - currentTimestamp;
        // Calculate how many missing points to add
        const missingIntervals = Math.floor(gap / sampleInterval) - 1;
        // Add missing data points with NAN_STRING (only executes if missingIntervals > 0)
        for (let j = 1; j <= missingIntervals; j++) {
            const missingTimestamp = currentTimestamp + j * sampleInterval;
            newValues.push([missingTimestamp, NAN_STRING]);
        }
    }
    // Add the last element
    newValues.push(orginalValues[orginalValues.length - 1]);
    // add missing data points for the ending time
    for (let i = orginalValues[orginalValues.length - 1][0] + sampleInterval; i < startingTimeStamp + sampleDuration; i += sampleInterval) {
        newValues.push([i, NAN_STRING]);
    }
    return newValues;
}
// get the value for the based value
// TODO: We need to handle the negative value in the future
export const getRelativeValue = (value, base) => {
    return value / (base || 1);
};
export const relativeDatumToOriginalDatum = (datum, base) => {
    // $FlowFixMe
    return Object.fromEntries(Object.entries(datum).map(([key, value]) => [
        key,
        getAbsoluteValue(value, base),
    ]));
};
export const getAbsoluteValue = (relativeValue, base) => {
    return relativeValue * (base || 1);
};
// extract the labels from getTooltipLabel function to define the domain in color
export const getColorDomains = (series) => {
    return series.map((serie) => {
        return normlizeVegaFieldName(serie.getTooltipLabel(serie.metricPrefix, serie.resource));
    });
};
