var chartOptions = {
    colors:['#008ffb', '#f08681'],
    series: [
        {
            name: 'Ping',
            data: [null]
        },
        {
            name: 'Pakke Tap',
            type: 'area',
            data: [null]
        }
    ],
    chart: {
        height: '100%',
        id: 'realtime',
        type: 'area',
        animations: {
            enabled: false,
        },
        toolbar: {
            show: false
        },
        zoom: {
            enabled: false
        },
    },
    dataLabels: {
        enabled: false,
    },
    stroke: {
        curve: 'straight'
    },
    markers: {
        size: 0
    },
    xaxis: {
        type: 'datetime',
        labels: {
            datetimeUTC: false,
        },
    },
    yaxis: [
        {
            seriesName: 'Ping',
            labels: {
                formatter: function (val) {
                    if (val == null) {
                        return 0;
                    }
                    return val.toFixed(1);
                },
            }
        },
        {
            seriesName: 'Pakke Tap',
            min:0,
            max:100,
            opposite: true,
            
            labels: {
                formatter: function (val) {
                    if (val == null) {
                        return 0 + '%';
                    }
                    return val.toFixed(0) + "%";
                },
            }
        }
    ],
    legend: {
        show: false
    },
};
var timeRangeInSeconds = 0;
var chartLatest;
var chartHasFetchedTimeRange = false;
var chartElement;
var chartPingSeries = [];
var chartPacketLossSeries = [];
var scanId;

const queryParam = new Proxy(new URLSearchParams(window.location.search), {
    get: (searchParams, prop) => searchParams.get(prop),
});

document.body.onload = async function() {
    chartElement = new ApexCharts(document.querySelector("#liveChart"), chartOptions);
    chartElement.render();

    timeRangeInSeconds = timeRangeSelector[timeRangeSelector.selectedIndex].attributes.value.nodeValue;

    await update_summary();
    update_chart();
    window.setInterval(async function() {
        update_summary();
        update_chart();
    }, 5000)
};

timeRangeSelector.onchange = function(event) {
    timeRangeInSeconds = event.srcElement[event.srcElement.selectedIndex].attributes.value.nodeValue;

    if (timeRangeInSeconds == 'Details') {
        if (queryParam.ref_uuid !== null) {
            window.location.href = './?p=scan_details&ref_uuid=' + queryParam.ref_uuid + '&scan_id=' + scanId;
        } else {
            window.location.href = './?p=scan_details&host=' + queryParam.host + '&scan_id=' + scanId;
        }
    }

    // TODO: a very rare race condition may occur when switching too fast between time ranges can cause the chart to show wrong data
    // cancel the update interval and start it again

    // reset chart
    chartHasFetchedTimeRange = false;
    chartPingSeries = [];
    chartPacketLossSeries = [];
    chartElement.updateSeries([
        {
            data: chartPingSeries
        },
        {
            data: chartPacketLossSeries
        }
    ]);

    update_chart();
    update_summary();
};

async function update_summary() {
    if (queryParam.ref_uuid !== null) {
        var response = await fetch('./?p=api_stats&ref_uuid=' + queryParam.ref_uuid + '&since=' + (Math.floor(Date.now() / 1000) - timeRangeInSeconds));
    } else {
        var response = await fetch('./?p=api_stats&host=' + queryParam.host + '&since=' + (Math.floor(Date.now() / 1000) - timeRangeInSeconds));
    }

    if (response.status == 400) {
        setTimeout(() => {
            window.location.reload();
        }, 1000);
        return;
    }

    if (response.status !== 200) {
        return;
    }

    let jsonResponse = await response.json();

    scanId = jsonResponse.scan_id;

    let resp_ping              = jsonResponse.ping_latest;
    let resp_packet_loss       = jsonResponse.packet_loss_percentage;
    let resp_uptime            = jsonResponse.uptime_percentage;
    let resp_connection_status = jsonResponse.connection_status;

    if (resp_ping == null) {
        ping.innerHTML        = 'Feilet';
    } else {
        ping.innerHTML        = resp_ping + ' ms';
    }

    packet_loss.innerHTML = resp_packet_loss + ' %';
    uptime.innerHTML      = resp_uptime + ' %';

    if (resp_connection_status == 'ONLINE') {
        connection_status.className = 'sign-text alert-success'
        connection_status.innerHTML = 'Online';
    }
    if (resp_connection_status == 'UNSTABLE') {
        connection_status.className = 'sign-text alert-warning'
        connection_status.innerHTML = 'Ustabilt';
    }
    if (resp_connection_status == 'OFFLINE') {
        connection_status.className = 'sign-text alert-danger'
        connection_status.innerHTML = 'Offline';
    }
}

async function update_chart()
{
    if (!chartHasFetchedTimeRange) {
        var response = await fetch('./?p=api_chart&limit_length=1000&scan_id=' + scanId + '&since=' + (Math.floor(Date.now() / 1000) - timeRangeInSeconds));
        chartHasFetchedTimeRange = true;
    } else {
        var response = await fetch('./?p=api_chart&scan_id=' + scanId + '&since=' + chartLatest);
    }

    if (response.status === 204) {
        return;
    }

    let jsonResponse = await response.json();

    chartLatest = jsonResponse.latest; 

    jsonResponse.pings.forEach(ping => {
        let newDate = new Date(ping.date_added + ' UTC');
        chartPingSeries.push({ x: newDate.toString(), y: ping.ping_avg});
    });

    // remove old pings
    for (let i = 0; i < chartPingSeries.length; i++) {
        let pingEpoch = Math.floor((new Date(chartPingSeries[i].x)).getTime() / 1000);
        if (pingEpoch < chartLatest - timeRangeInSeconds) {
            chartPingSeries.splice(i, 1);
        }
    } 

    jsonResponse.pings.forEach(ping => {
        let newDate = new Date(ping.date_added + ' UTC');
        if (ping.pkt_transmitted != ping.pkt_received) {
            let pktLossPercentage = ping.pkt_received / ping.pkt_transmitted * 100;
            pktLossPercentage = 100 - pktLossPercentage;
            chartPacketLossSeries.push({ x: newDate.toString(), y: pktLossPercentage});
        } else {
            chartPacketLossSeries.push({ x: newDate.toString(), y: 0});
        }
    });

    for (let i = 0; i < chartPacketLossSeries.length; i++) {
        let pingEpoch = Math.floor((new Date(chartPacketLossSeries[i].x)).getTime() / 1000);
        if (pingEpoch < chartLatest - timeRangeInSeconds) {
            chartPacketLossSeries.splice(i, 1);
        }
    } 

    chartElement.updateSeries([
        {
            name: 'Ping',
            data: chartPingSeries
        },
        {
            name: 'Pakke Tap',
            data: chartPacketLossSeries 
        }
    ]);
}