/**
 * @typedef {Object} StreamerOutputData
 * @property {number} index - The index of the Barix connection.
 * @property {string} channel - The channel name of the Barix connection.
 * @property {string} ipaddress - The IP address of the Barix connection.
 * @property {number} bufferRemain - The remaining buffer size of the Barix connection.
 * @property {boolean} isPlaying - true = playback started, false = playback stopped
 * @property {number} vu - The VU level of the Barix connection, 0 to 100.
 */


/**
 * @typedef {Object} PagingQueue
 * @property {number} index - The index of the paging queue item.
 * @property {string} Date_Time - The date and time of the paging queue item.
 * @property {string} Source - The source of the paging queue item.
 * @property {string} Type - The type of the paging queue item.
 * @property {string} Message - The message of the paging queue item.
 * @property {string} BroadcastZones - The broadcast zones of the paging queue item.
 */

/**
 * @typedef {Object} StreamerCard
 * @property {JQuery<HTMLElement> | null} title - The jQuery result should be <h4> element.
 * @property {JQuery<HTMLElement> | null} ip - The jQuery result should be <h6> element.
 * @property {JQuery<HTMLElement> | null} buffer - The jQuery result should be <h6> element.
 * @property {JQuery<HTMLElement> | null} status - The jQuery result should be <p> element.
 * @property {JQuery<HTMLElement> | null} vu - The jQuery result should be <progress-bar> element.
 */

function getCardByIndex(index) {
    let obj = {
        // title is <h4> element wiht id `streamertitle${index}`, with index as two digit number, e.g. 01, 02, 03
        title: $(`#streamertitle${index.toString().padStart(2, '0')}`),
        // ip is <h6> element with id `streamerip${index}`, with index as two digit number, e.g. 01, 02, 03
        ip: $(`#streamerip${index.toString().padStart(2, '0')}`),
        // buffer is <h6> element with id `streamerbuffer${index}`, with index as two digit number, e.g. 01, 02, 03
        buffer: $(`#streamerbuffer${index.toString().padStart(2, '0')}`),
        // status is <p> element with id `streamerstatus${index}`, with index as two digit number, e.g. 01, 02, 03
        status: $(`#streamerstatus${index.toString().padStart(2, '0')}`),
        // vu is <progress-bar> element with id `streamervu${index}`, with index as two digit number, e.g. 01, 02, 03
        vu: $(`#streamervu${index.toString().padStart(2, '0')} .progress-bar`),
    }
    return obj;
}

/**
 * Updates the streamer card with the provided values.
 * @param {StreamerOutputData[]} values 
 */
function UpdateStreamerCard(values) {
    if (!Array.isArray(values) || values.length === 0) return;
    
    function setProgress(index, $bar, value, max = 100) {
        const v = Number(value ?? 0);
        const pct = Math.max(0, Math.min(100, Math.round((v / max) * 100)));
        //if (index!==1) return; // only update index 1 for testing
        //console.log(`setProgress: index=${index}, value=${v}, pct=${pct}`);
        $bar
            .attr('aria-valuenow', v)     // semantic value
            .css('width', pct + '%')      // visual width
            .text(pct);             // optional label
    }
    for (let i = 1; i <= 64; i++) {
        let vv = values.find(v => v.index === i);
        let card = getCardByIndex(i);
        if (vv) {
            // there is value for this index
            if (card.title) card.title.text(vv.channel ? vv.channel : `Channel ${i.toString().padStart(2, '0')}`);
            if (card.ip) card.ip.text(`IP Address: ${vv.ipaddress ? vv.ipaddress : 'N/A'}`);
            if (card.buffer) card.buffer.text(`Buffer: ${vv.bufferRemain !== undefined && vv.bufferRemain !== null ? vv.bufferRemain.toString() : 'N/A'}`);
            if (card.status) card.status.text(`Status: ${vv.isPlaying ? 'Playing' : 'Stopped'}`);
            if (card.vu) {
                setProgress(i, card.vu, vv.vu, 100);
            }
        } else {
            // no value for this index, disable the card
            if (card.title) card.title.text(`Channel ${i.toString().padStart(2, '0')}`);
            if (card.ip) card.ip.text(`IP Address: N/A`);
            if (card.buffer) card.buffer.text(`Buffer: N/A`);
            if (card.status) card.status.text(`Status: Disconnected`);
            if (card.vu) {
                setProgress(i, card.vu, 0, 100);
            }
        }
    }
}

/**
 * @type {PagingQueue[]}
 */
window.PagingQueue = [];
/**
 * @type {JQuery<HTMLElement> | null}
 */
window.selectedpagingrow = null;

/**
 * @typedef {Object} QueueTable
 * @property {number} index - The index of the automatic queue item.
 * @property {string} Date_Time - The date and time of the automatic queue item.
 * @property {string} Source - The source of the automatic queue item.
 * @property {string} Type - The type of the automatic queue item.
 * @property {string} Message - The message of the automatic queue item.
 * @property {string} SB_TAGS - The SB_TAGS of the automatic queue item.
 * @property {string} BroadcastZones - The broadcast zones of the automatic queue item.
 * @property {number} Repeat - The repeat count of the automatic queue item.
 * @property {string} Language - The language of the automatic queue item.
 */

/**
 * @type {QueueTable[]}
 */
window.QueueTable = [];
/**
 * @type {JQuery<HTMLElement> | null}
 */
window.selectedautomaticrow = null;

/**
 * Fills the paging queue table body with the provided data.
 * @param {PagingQueue[]} vv array of PagingQueue objects
 * @returns 
 */
function fill_pagingqueuetablebody(vv) {
    $('#pagingqueuetable').empty();
    if (!Array.isArray(vv) || vv.length === 0) return;
    vv.forEach(item => {
        // fill index and description columns using item properties  
        $('#pagingqueuetable').append(`<tr>
            <td>${item.index}</td>
            <td>${item.date_Time}</td>
            <td>${item.source}</td>
            <td>${item.type}</td>
            <td>${item.message}</td>
            <td>${item.broadcastZones}</td>
        </tr>`);
        let $addedrow = $('#pagingqueuetable tr:last');
        $addedrow.off('click').on('click', function () {
            if (window.selectedpagingrow) {
                window.selectedpagingrow.find('td').css('background-color', '');
                if (window.selectedpagingrow.is($(this))) {
                    window.selectedpagingrow = null;
                    $('#removepagingqueue').prop('disabled', true);
                    return;
                }
            }
            window.selectedpagingrow = $(this);
            window.selectedpagingrow.find('td').css('background-color', 'lightblue');
            $('#removepagingqueue').prop('disabled', false);
        });
    });
}

/**
 * Fills the automatic queue table body with the provided data.
 * @param {QueueTable[]} vv array of QueueTable objects
 * @returns 
 */
function fill_automaticqueuetablebody(vv) {
    $('#automaticqueuetable').empty();
    if (!Array.isArray(vv) || vv.length === 0) return;
    vv.forEach(item => {
        // fill index and description columns using item properties
        //console.log("fill_automaticqueuetablebody: item", item);
        $('#automaticqueuetable').append(`<tr>
            <td>${item.index}</td>
            <td>${item.date_Time}</td>
            <td>${item.source}</td>
            <td>${item.type}</td>
            <td>${item.message}</td>
            <td>${item.broadcastZones}</td>
        </tr>`);
        let $addedrow = $('#automaticqueuetable tr:last');
        $addedrow.off('click').on('click', function () {
            if (window.selectedautomaticrow) {
                window.selectedautomaticrow.find('td').css('background-color', '');
                if (window.selectedautomaticrow.is($(this))) {
                    window.selectedautomaticrow = null;
                    $('#removeautomatictable').prop('disabled', true);
                    return;
                }
            }
            window.selectedautomaticrow = $(this);
            window.selectedautomaticrow.find('td').css('background-color', 'lightblue');
            $('#removeautomatictable').prop('disabled', false);
        });
    });
}

function reloadPagingQueue(APIURL = "QueuePaging/") {
    window.PagingQueue = [];
    fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => {
        if (Array.isArray(okdata) && okdata.length > 0) {
            window.PagingQueue.push(...okdata);
            fill_pagingqueuetablebody(window.PagingQueue);
        } else {
            console.log("reloadPagingQueue: okdata is not array");
        }
    }, (errdata) => {
        console.log("reloadPagingQueue: errdata", errdata);
    });
}

function reloadAutomaticQueue(APIURL = "QueueTable/") {
    window.QueueTable = [];
    fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => {
        if (Array.isArray(okdata) && okdata.length > 0) {
            window.QueueTable.push(...okdata);
            fill_automaticqueuetablebody(window.QueueTable);
        } else {
            console.log("reloadAutomaticQueue: okdata is not array");
        }
    }, (errdata) => {
        console.log("reloadAutomaticQueue: errdata", errdata);
    });
}

function RemovePagingQueueByIndex(index, APIURL = "QueuePaging/") {
    fetchAPI(APIURL + "DeleteByIndex/" + index, "DELETE", {}, null, (okdata) => {
        console.log("RemovePagingQueueByIndex: okdata", okdata);
        reloadPagingQueue(APIURL);
    }, (errdata) => {
        console.log("RemovePagingQueueByIndex: errdata", errdata);
    });
}

function RemoveAutomaticQueueByIndex(index, APIURL = "QueueTable/") {
    fetchAPI(APIURL + "DeleteByIndex/" + index, "DELETE", {}, null, (okdata) => {
        console.log("RemoveAutomaticQueueByIndex: okdata", okdata);
        reloadAutomaticQueue(APIURL);
    }, (errdata) => {
        console.log("RemoveAutomaticQueueByIndex: errdata", errdata);
    });
}

$(document).ready(function () {
    console.log("overview.js loaded");



    $('#clearpagingqueue').off('click').on('click', function () {
        DoClear("QueuePaging/", "Paging Queue", (okdata) => {
            reloadPagingQueue();
            alert("Success clear Paging Queue: " + okdata.message);
        }, (errdata) => {
            alert("Error clear Paging Queue: " + errdata.message);
        });
    });
    $('#removepagingqueue').off('click').on('click', function () {
        if (window.selectedpagingrow) {
            let cells = window.selectedpagingrow.find('td');
            let index = Number(cells.eq(0).text());
            let description = cells.eq(1).text();
            if (!isNaN(index) && description && description.length > 0) {
                if (confirm(`Are you sure to remove Paging Queue Index: ${index} Description: ${description} ?`)) {
                    RemovePagingQueueByIndex(index);
                    window.selectedpagingrow = null;
                    $('#removepagingqueue').prop('disabled', true);
                }
            }
        }
    });



    $('#clearautomatictable').off('click').on('click', function () {
        DoClear("QueueTable/", "Automatic Queue", (okdata) => {
            reloadAutomaticQueue();
            alert("Success clear Automatic Queue: " + okdata.message);
        }, (errdata) => {
            alert("Error clear Automatic Queue: " + errdata.message);
        });
    });
    $('#removeautomatictable').off('click').on('click', function () {
        if (window.selectedautomaticrow) {
            let cells = window.selectedautomaticrow.find('td');
            let index = Number(cells.eq(0).text());
            let description = cells.eq(1).text();
            if (!isNaN(index) && description && description.length > 0) {
                if (confirm(`Are you sure to remove Automatic Queue Index: ${index} Description: ${description} ?`)) {
                    RemoveAutomaticQueueByIndex(index);
                    window.selectedautomaticrow = null;
                    $('#removeautomatictable').prop('disabled', true);
                }
            }
        }
    });

    let intervaljob1 = null;
    let intervaljob2 = null;
    function runIntervalJob() {
        if (intervaljob1) clearInterval(intervaljob1);
        intervaljob1 = setInterval(() => {
            sendCommand("getStreamerOutputs", "");
        }, 100);
        if (intervaljob2) clearInterval(intervaljob2);
        intervaljob2 = setInterval(() => {
            sendCommand("getPagingQueue", "");
            sendCommand("getAASQueue", "");
        }, 2000);
        console.log("overview.js interval job started");
    }

    runIntervalJob();

    window.addEventListener('ws_connected', () => {
        console.log("overview.js ws_connected event triggered");
        runIntervalJob();
    });

    window.addEventListener('ws_disconnected', () => {
        console.log("overview.js ws_disconnected event triggered");
        if (intervaljob) clearInterval(intervaljob);
        intervaljob = null;
    });
    window.addEventListener('ws_message', (event) => {
        let rep = event.detail;
        let cmd = rep.reply;
        let data = rep.data;
        if (cmd && cmd.length > 0) {
            switch (cmd) {
                case "getPagingQueue":
                    let pq = JSON.parse(data);
                    //console.log("getPagingQueue:", pq);
                    window.PagingQueue = [];
                    if (Array.isArray(pq) && pq.length > 0) {
                        window.PagingQueue.push(...pq);
                    }
                    fill_pagingqueuetablebody(window.PagingQueue);
                    break;
                case "getAASQueue":
                    let aq = JSON.parse(data);
                    //console.log("getAASQueue:", aq);
                    window.QueueTable = [];
                    if (Array.isArray(aq) && aq.length > 0) {
                        window.QueueTable.push(...aq);
                    } 
                    fill_automaticqueuetablebody(window.QueueTable);
                    break;
                case "getStreamerOutputs":
                    /**
                     * @type {StreamerOutputData[]}
                     */
                    let so = JSON.parse(data);
                    UpdateStreamerCard(so);
                    break;
            }
        }
    });

    $(window).on('beforeunload', function () {
        console.log("overview.js beforeunload event triggered");
        clearInterval(intervaljob1);
        clearInterval(intervaljob2);
        intervaljob1 = null;
        intervaljob2 = null;
    });
});
