/**
 * @typedef {Object} SoundBank
 * @property {number} index
 * @property {string} description
 * @property {string} tag
 * @property {string} category
 * @property {string} language
 * @property {string} voiceType
 * @property {string} path
 */

/**
 * @typedef {Object} MessageBank
 * @property {number} index
 * @property {string} description
 * @property {string} language
 * @property {number} aNN_ID
 * @property {string} voice_Type
 * @property {string} message_Detail
 * @property {string} message_TAGS
 */

/**
 * @typedef {Object} LanguageBank
 * @property {number} index
 * @property {string} tag
 * @property {string} language
 * @
 */

/**
 * @typedef {Object} ScheduleBank
 * @property {number} index
 * @property {string} description
 * @property {string} day
 * @property {string} time
 * @property {string} soundpath
 * @property {number} repeat
 * @property {boolean} enable
 * @property {string} broadcastZones
 * @property {string} language
 */

/**
 * @typedef {Object} Log
 * @property {number} index
 * @property {string} datenya
 * @property {string} timenya
 * @property {string} machine
 * @property {string} description
 */

/**
 * @typedef {Object} Select2item
 * @property {number} id
 * @property {string} text
 */

/**
 * List of Soundbank data loaded from server
 * @type {SoundBank[]}
 */
let soundbankdata = [];
/**
 * Currently selected soundbank row in the table
 * @type {JQuery<HTMLElement>|null}
 */
let selectedsoundrow = null;
/**
 * List of Messagebank data loaded from server
 * @type {MessageBank[]}
 */
let messagebankdata = [];
/**
 * Currently selected messagebank row in the table
 * @type {JQuery<HTMLElement>|null}
 */
let selectedmessagerow = null;
/** List of Languagebank data loaded from server
 * @type {LanguageBank[]}
 */
let languagebankdata = [];
/**
 * Currently selected languagebank row in the table
 * @type {JQuery<HTMLElement>|null}
 */
let selectedlanguagerow = null;
/** List of Schedulebank data loaded from server
 * @type {ScheduleBank[]}
 */
let schedulebankdata = [];
/**
 * Currently selected schedulebank row in the table
 * @type {JQuery<HTMLElement>|null}
 */
let selectedschedulerow = null;
/** List of Log data loaded from server
 * @type {Log[]}
 */
let logdata = [];
/**
 * List of sound files in the soundbank directory, that ends with .wav or .mp3
 * @type {string[]}
 */
let soundbankfiles = [];
/**
 * Select2 data source
 * See https://select2.org/data-sources/formats
 * @type {Object}
 * @property {Select2item[]} results
 */
let select2results = {
    results: []
};

/**
 * List of voice types available
 * @type {string[]}
 */
let voiceTypes = [];
/**
 * List of categories available
 * @type {string[]}
 */
let categories = [];
/**
 * List of languages available
 * @type {string[]}
 */
let languages = [];

/**
 * List of scheduled days available
 * @type {string[]}
 */
let scheduledays = []


/**
     * Fill soundbank table body with values
     * @param {SoundBank[]} vv values to fill
    */
function fill_soundbanktablebody(vv) {
    $('#soundbanktablebody').empty();
    if (!Array.isArray(vv) || vv.length === 0) return;
    vv.forEach(item => {
        const row = `<tr>
                     <td>${item.index}</td>
                     <td>${item.description}</td>
                     <td>${item.tag}</td>
                     <td>${item.category}</td>
                     <td>${item.language}</td>
                     <td>${item.voiceType}</td>
                     <td>${item.path}</td>
                     </tr>`;
        $('#soundbanktablebody').append(row);
        let $addedrow = $('#soundbanktablebody tr:last');
        $addedrow.on('click', function () {
            if (selectedsoundrow) {
                selectedsoundrow.find('td').css('background-color', '');
                if (selectedsoundrow.is($(this))) {
                    selectedsoundrow = null;
                    $('#btnRemove').prop('disabled', true);
                    $('#btnEdit').prop('disabled', true);
                    return;
                }
            }
            $(this).find('td').css('background-color', '#ffeeba');
            selectedsoundrow = $(this);
            $('#btnRemove').prop('disabled', false);
            $('#btnEdit').prop('disabled', false);
        });
    });


    $('#tablesize').text("Table Size: " + vv.length);
}

/**
 * Fill messagebank table body with values
* @param {MessageBank[]} vv values to fill
*/
function fill_messagebanktablebody(vv) {
    $('#messagebanktablebody').empty();
    if (!Array.isArray(vv) || vv.length === 0) return;
    vv.forEach(item => {
        const row = `<tr>
                     <td>${item.index}</td>
                     <td>${item.description}</td>
                     <td>${item.language}</td>
                     <td>${item.aNN_ID}</td>
                     <td>${item.voice_Type}</td>
                     <td>${item.message_Detail}</td>
                     <td>${item.message_TAGS}</td>
                            </tr>`;
        $('#messagebanktablebody').append(row);
        let $addedrow = $('#messagebanktablebody tr:last');
        $addedrow.click(function () {
            if (selectedmessagerow) {
                selectedmessagerow.find('td').css('background-color', '');
                if (selectedmessagerow.is($(this))) {
                    selectedmessagerow = null;
                    $('#btnRemove').prop('disabled', true);
                    $('#btnEdit').prop('disabled', true);
                    return;
                }
            }
            $addedrow.find('td').css('background-color', '#ffeeba');
            selectedmessagerow = $addedrow;
            $('#btnRemove').prop('disabled', false);
            $('#btnEdit').prop('disabled', false);
        });
    });

    console.log("loaded " + vv.length + " messagebank items");
}

/**
 * Fill languagebank table body with values
 * @param {LanguageBank[]} vv values to fill
 */
function fill_languagebanktablebody(vv) {
    $('#languagebanktablebody').empty();
    if (!Array.isArray(vv) || vv.length === 0) return;
    vv.forEach(item => {
        const row = `<tr>
                     <td>${item.index}</td>
                     <td>${item.tag}</td>
                     <td>${item.language}</td>
                     </tr>`;
        $('#languagebanktablebody').append(row);
        let $addedrow = $('#languagebanktablebody tr:last');
        $addedrow.click(function () {
            if (selectedlanguagerow) {
                selectedlanguagerow.find('td').css('background-color', '');
                if (selectedlanguagerow.is($(this))) {
                    selectedlanguagerow = null;
                    $('#btnRemove').prop('disabled', true);
                    $('#btnEdit').prop('disabled', true);
                    return;
                }
            }
            $addedrow.find('td').css('background-color', '#ffeeba');
            selectedlanguagerow = $addedrow;
            $('#btnRemove').prop('disabled', false);
            $('#btnEdit').prop('disabled', false);
        });
    });
    console.log("loaded " + vv.length + " languagebank items");
}

/**
 * Fill schedulebank table body with values
 * @param {ScheduleBank[]} vv values to fill
 */
function fill_schedulebanktablebody(vv) {
    $('#schedulebanktablebody').empty();
    if (!Array.isArray(vv) || vv.length === 0) return;
    vv.forEach(item => {
        const row = `<tr>
                     <td>${item.index}</td>
                     <td>${item.description}</td>
                     <td>${item.day}</td>
                     <td>${item.time}</td>
                     <td>${item.soundpath}</td>
                     <td>${item.repeat}</td>
                     <td>${item.enable}</td>
                     <td>${item.broadcastZones}</td>
                     <td>${item.language}</td>
                     </tr>`;
        $('#schedulebanktablebody').append(row);
        let $addedrow = $('#schedulebanktablebody tr:last');
        $addedrow.click(function () {
            if (selectedschedulerow) {
                selectedschedulerow.find('td').css('background-color', '');
                if (selectedschedulerow.is($(this))) {
                    selectedschedulerow = null;
                    $('#btnRemove').prop('disabled', true);
                    $('#btnEdit').prop('disabled', true);
                    return;
                }
            }
            $addedrow.find('td').css('background-color', '#ffeeba');
            selectedschedulerow = $addedrow;
            $('#btnRemove').prop('disabled', false);
            $('#btnEdit').prop('disabled', false);
        });
    });
    console.log("loaded " + vv.length + " schedulebank items");
}

/**
 * Fill log table body with values
 * @param {Log[]} vv values to fill
 */
function fill_logtablebody(vv) {
    $('#logtablebody').empty();
    if (!Array.isArray(vv) || vv.length === 0) return;
    vv.forEach(item => {
        const row = `<tr>
                     <td>${item.index}</td>
                     <td>${item.datenya}</td>
                     <td>${item.timenya}</td>
                     <td>${item.machine}</td>
                     <td>${item.description}</td>
                     </tr>`;
        $('#logtablebody').append(row);
    });
    console.log("loaded " + vv.length + " log items");
}

/**
 * WebSocket connection
 * @type {WebSocket}
 */
let ws = null;

/**
 * Send a command to the WebSocket server.
 * @param {String} command command to send
 * @param {String} data data to send
 */
function sendCommand(command, data) {
    if (ws.readyState === WebSocket.OPEN) {
        ws.send(JSON.stringify({ command, data }));
    } else {
        console.error('WebSocket is not open');
    }
}

/**
 * Fetch API helper function
 * @param {string} endpoint Endpoint URL
 * @param {string} method Method (GET, POST, etc.)
 * @param {Object} headers Headers to include in the request
 * @param {Object} body Body of the request
 * @param {Function} cbOK Callback function for successful response
 * @param {Function} cbError Callback function for error response
 */
function fetchAPI(endpoint, method, headers = {}, body = null, cbOK, cbError) {
    let url = window.location.origin + "/api/" + endpoint;
    let options = {
        method: method,
        headers: headers
    }
    if (body !== null) {
        options.body = JSON.stringify(body);
        if (!options.headers['Content-Type']) {
            options.headers['Content-Type'] = 'application/json';
        }
    }
    console.log("About to fetch from " + url + " with options", options);
    fetch(url, options)
        .then(response => {
            console.log("fetchAPI: received response", response);
            if (!response.ok) {
                throw new Error('Network response was not ok ' + response.statusText);
            }
            return response.json();
        })
        .then(data => {
            console.log("fetchAPI: received data", data);
            cbOK(data);
        })
        .catch(error => {
            console.error('There was a problem with the fetch operation:', error);
            cbError(error);
        });
}

/**
 * Reload sound bank from server
 * @param {String} APIURL API URL endpoint
 */
function reloadSoundBank(APIURL) {
    soundbankdata = [];
    console.log("reloadSoundBank: fetching from " + APIURL + "List");
    fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => {
        console.log("reloadSoundBank: received data", okdata);
        if (Array.isArray(okdata)) {
            soundbankdata = okdata;
            selectedsoundrow = null;
            fill_soundbanktablebody(soundbankdata);
        }
    }, (errdata) => {
        alert("Error loading soundbank: " + errdata.message);
    });
}

/**
* Reload message bank from server
* @param {string} APIURL API URL endpoint
*/
function reloadMessageBank(APIURL) {
    messagebankdata = [];
    fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => {
        if (Array.isArray(okdata)) {
            messagebankdata = okdata;
            selectedmessagerow = null;
            fill_messagebanktablebody(messagebankdata);
        }
    }, (errdata) => {
        alert("Error loading messagebank: " + errdata.message);
    });
}

/**
 * Reload language bank from server
 * @param {string} APIURL API URL endpoint
 */
function reloadLanguageBank(APIURL) {
    languagebankdata = [];
    fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => {
        if (Array.isArray(okdata)) {
            languagebankdata = okdata;
            selectedlanguagerow = null;
            fill_languagebanktablebody(languagebankdata);
        }
    }, (errdata) => {
        alert("Error loading languagebank: " + errdata.message);
    });
}

/**
 * Reload timer bank from server
 * @param {string} APIURL API URL endpoint
 */
function reloadTimerBank(APIURL) {
    schedulebankdata = [];
    fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => {
        if (Array.isArray(okdata)) {
            schedulebankdata = okdata.data;
            selectedschedulerow = null;
            fill_schedulebanktablebody(schedulebankdata);
        }
    }, (errdata) => {
        alert("Error loading schedulebank: " + errdata.message);
    });
}

/**
 * Reload logs from server with date and filter
 * @param {String} APIURL API URL endpoint 
 * @param {String} date date in format dd/MM/yyyy
 * @param {String} filter log filter text
 */
function reloadLogs(APIURL, date, filter) {
    fetchAPI(APIURL + "List/" + date + "/" + filter, "GET", {}, null, (okdata) => {
        $('#logcontent').val(okdata.data);
    }, (errdata) => {
        alert("Error loading logs: " + errdata.message);
    });
}

/**
 * Reload soundbank files from server
 * @param {String} APIURL API URL endpoint (default "SoundBank/")
 */
function regetSoundbankFiles(APIURL = "SoundBank/") {
    soundbankfiles = [];
    fetchAPI(APIURL + "ListFiles", "GET", {}, null, (okdata) => {
        // okdata is a string contains elements separated by semicolon ;
        if (Array.isArray(okdata)) {
            soundbankfiles = okdata.filter(item => item.trim().length > 0);
            //console.log("Loaded " + soundbankfiles.length + " sound files : " + soundbankfiles.join(", ") );

            // refill select2results
            select2results.results = soundbankfiles.map((item, index) => ({ id: index + 1, text: item }));
        } else console.log("regetSoundbankFiles: okdata is not array");
    }, (errdata) => {
        alert("Error loading soundbank files: " + errdata.message);
    });
}

/**
 * Reload voice types from server
 */
function getVoiceTypes() {
    voiceTypes = [];
    fetchAPI("VoiceType", "GET", {}, null, (okdata) => {
        // okdata is a string contains elements separated by semicolon ;
        if (Array.isArray(okdata)) {
            voiceTypes = okdata.filter(item => item.trim().length > 0);
            //console.log("Loaded " + voiceTypes.length + " voice types : " + voiceTypes.join(", "));
        } else console.log("getVoiceTypes: okdata is not array");
    }, (errdata) => {
        alert("Error loading voice types: " + errdata.message);
    });
}

/**
 * Reload categories from server
 */
function getCategories() {
    categories = [];
    fetchAPI("Category", "GET", {}, null, (okdata) => {
        // okdata is a string contains elements separated by semicolon ;
        if (Array.isArray(okdata)) {
            categories = okdata.filter(item => item.trim().length > 0);
            //console.log("Loaded " + categories.length + " categories : " + categories.join(", "));
        } else console.log("getCategories: okdata is not array");
    }, (errdata) => {
        alert("Error loading categories: " + errdata.message);
    });
}

/**
 * Reload languages from server
 */
function getLanguages() {
    languages = [];
    fetchAPI("Language", "GET", {}, null, (okdata) => {
        // okdata is a string contains elements separated by semicolon ;
        if (Array.isArray(okdata)) {
            languages = okdata.filter(item => item.trim().length > 0);
            //console.log("Loaded " + languages.length + " languages : " + languages.join(", ") );
        } else console.log("getLanguages: okdata is not array");
    }, (errdata) => {
        alert("Error loading languages: " + errdata.message);
    });
}

/**
 * Reload scheduled days from server
 */
function getScheduledDays() {
    scheduledays = [];
    fetchAPI("ScheduleDay", "GET", {}, null, (okdata) => {
        // okdata is a string contains elements separated by semicolon ;
        if (Array.isArray(okdata)) {
            scheduledays = okdata.filter(item => item.trim().length > 0);
            //console.log("Loaded " + scheduledays.length + " scheduled days : " + scheduledays.join(", ") );
        } else console.log("getScheduledDays: okdata is not array");
    }, (errdata) => {
        alert("Error loading scheduled days: " + errdata.message);
    });
}

/**
 * Export mechanism to XLSX file
 * @param {String} APIURL API URL endpoint
 * @param {String} filename target filename
 */
function DoExport(APIURL, filename) {
    // send GET request to APIURL + "ExportXLSX"
    // reply Content-Type is application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
    // reply Content-Disposition: attachment; filename=filename
    // Use fetch to download the XLSX file as a blob and trigger download
    fetch("/api/" + APIURL + "ExportXLSX", {
        method: "GET",
        headers: {}
    })
    .then(response => {
        if (!response.ok) throw new Error('Network response was not ok ' + response.statusText);
        return response.blob();
    })
    .then(blob => {
        const url = window.URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = filename;
        document.body.appendChild(a);
        a.click();
        a.remove();
        window.URL.revokeObjectURL(url);
    })
    .catch(error => {
        alert("Error export to " + filename + ": " + error.message);
    });
    return; // prevent the rest of the function from running


    
}

/**
 * Import mechanism from XLSX file
 * @param {String} APIURL API URL endpoint
 * @param {Function<Object>} cbOK function that accept object data
 * @param {Function<Error>} cbError function that accept error object
 */
function DoImport(APIURL, cbOK, cbError) {
    // Open file selection dialog that accepts only .xlsx files
    // then upload to server using fetchAPI at "api/ImportXLSX" with POST method
    let fileInput = document.createElement('input');
    fileInput.type = 'file';
    fileInput.accept = '.xlsx';
    fileInput.onchange = e => {
        let file = e.target.files[0];
        if (file) {
            let formData = new FormData();
            formData.append('file', file);
            fetch("/api/" + APIURL + "ImportXLSX", { method: 'POST', body: formData })
                .then(response => {
                    if (!response.ok) { throw new Error('Network response was not ok ' + response.statusText); }
                    return response.json();
                })
                .then(data => {
                    cbOK(data);
                })
                .catch(error => {
                    cbError(error);
                });
        } else {
            cbError(new Error("No file selected"));
        }
    };
    fileInput.click();
    fileInput.remove();
}


/**
 * App entry point
 */
$(document).ready(function () {
    document.title = "Automatic Announcement System"
    $('#onlineindicator').attr('src', '/assets/img/red_circle.png');
    getVoiceTypes();
    getCategories();
    getLanguages();
    getScheduledDays();
    regetSoundbankFiles();

    // Initialize WebSocket connection
    ws = new WebSocket(window.location.pathname + '/ws');

    ws.onopen = () => {
        console.log('WebSocket connection established');
        $('#onlineindicator').attr('src', '/assets/img/green_circle.png');
    };
    ws.onmessage = (event) => {
        let rep = JSON.parse(event.data);
        let cmd = rep.reply
        let data = rep.data;
        if (cmd && cmd.length > 0) {
            switch (cmd) {
                case "getCPUStatus":
                    $('#cpustatus').text("CPU Usage: " + data)
                    break;
                case "getMemoryStatus":
                    $('#ramstatus').text("Memory Usage: " + data)
                    break;
                case "getDiskStatus":
                    $('#diskstatus').text("Disk Usage: " + data)
                    break;
                case "getNetworkStatus":
                    $('#networkstatus').text("Network Usage: " + data)
                    break;
                case "getSystemTime":
                    $('#datetimetext').text(data)
                    break;

            }
        }
    };
    ws.onclose = () => {
        console.log('WebSocket connection closed');
        $('#onlineindicator').attr('src', '/assets/img/red_circle.png');
    };
    // ws.onerror = (error) => {
    //     console.error('WebSocket error:', error);
    // };



    setInterval(() => {
        sendCommand("getCPUStatus", "")
        sendCommand("getMemoryStatus", "")
        sendCommand("getDiskStatus", "")
        sendCommand("getNetworkStatus", "")
        sendCommand("getSystemTime", "")
    }, 1000)

    let sidemenu = new bootstrap.Offcanvas('#offcanvas-menu');
    $('#showmenu').click(() => { sidemenu.show(); })

    $('#homelink').click(() => {
        sidemenu.hide();
        $('#content').load('overview.html', function (response, status, xhr) {
            if (status === "success") {
                console.log("Overview content loaded successfully");
            }
        });
    });
    $('#soundbanklink').click(() => {
        sidemenu.hide();
        $('#content').load('soundbank.html', function (response, status, xhr) {
            if (status === "success") {
                console.log("Soundbank content loaded successfully");
                // initialize first state of buttons and text input
                $('#soundbanktablebody').empty();
                selectedsoundrow = null;
                let $btnClear = $('#btnClear');
                let $btnAdd = $('#btnAdd');
                let $btnRemove = $('#btnRemove');
                let $btnEdit = $('#btnEdit');
                let $btnExport = $('#btnExport');
                let $btnImport = $('#btnImport');
                let $modal = $('#soundbankmodal');
                $btnRemove.prop('disabled', true);
                $btnEdit.prop('disabled', true);
                let APIURL = "SoundBank/";


                reloadSoundBank(APIURL);
                $btnClear.click(() => {
                    if (confirm(`Are you sure want to clear Soundbank ? This procedure is not reversible`)) {
                        fetchAPI(APIURL + "List", "DELETE", {}, null, (okdata) => {
                            alert("Success clear soundbank" + okdata.message);
                            soundbankdata = []
                            selectedsoundrow = null;
                            fill_soundbanktablebody(soundbankdata);
                        }, (errdata) => {
                            alert("Error clear soundbank: " + errdata.message);
                        });
                    }
                });
                $btnAdd.click(() => {
                    $('.js-example-basic-single').select2({
                        placeholder: 'Select a sound file',
                        closeOnSelect: true,
                        data: select2results,
                    });
                    $modal.modal('show');
                    // event on Click save button
                    $modal.off('click.soundbanksave').on('click.soundbanksave', '#soundbanksave', function () {
                        $modal.modal('hide');
                    });
                    // event on Click close button
                    $modal.off('click.soundbankclose').on('click.soundbankclose', '#soundbankclose', function () {
                        $modal.modal('hide');
                    });
                });
                $btnRemove.click(() => {
                    if (selectedsoundrow) {
                        let cells = selectedsoundrow.find('td');
                        /** @type {SoundBank} */
                        let sb = {
                            index: cells.eq(0).text(),
                            description: cells.eq(1).text(),
                            tag: cells.eq(2).text(),
                            category: cells.eq(3).text(),
                            language: cells.eq(4).text(),
                            voiceType: cells.eq(5).text(),
                            path: cells.eq(6).text()
                        }
                        if (confirm(`Are you sure to delete soundbank [${sb.index}] Description=${sb.description} Tag=${sb.tag}?`)) {
                            fetchAPI(APIURL + "DeleteByIndex/" + sb.index, "DELETE", {}, null, (okdata) => {
                                alert("Success delete soundbank" + okdata.message);
                                soundbankdata = soundbankdata.filter(item => item.index !== sb.index);
                                selectedsoundrow = null;
                                fill_soundbanktablebody(soundbankdata);
                            }, (errdata) => {
                                alert("Error delete soundbank: " + errdata.message);
                            });
                        }
                    }
                });
                $btnEdit.click(() => {
                    if (selectedsoundrow) {
                        let cells = selectedsoundrow.find('td');
                        /** @type {SoundBank} */
                        let sb = {
                            index: cells.eq(0).text(),
                            description: cells.eq(1).text(),
                            tag: cells.eq(2).text(),
                            category: cells.eq(3).text(),
                            language: cells.eq(4).text(),
                            voiceType: cells.eq(5).text(),
                            path: cells.eq(6).text()
                        }
                        if (confirm(`Are you sure to edit soundbank [${sb.index}] Description=${sb.description} Tag=${sb.tag}?`)) {
                            $modal.modal('show');
                            $modal.off('hidden.bs.modal').on('hidden.bs.modal', function () {
                                const desc = $('#description').val();
                                console.log('Description input value:', desc);
                                // You can use desc here (e.g., send to server)
                            });
                        }
                    }
                });
                $btnExport.click(() => {
                    DoExport(APIURL, "soundbank.xlsx");
                });
                $btnImport.click(() => {
                    DoImport(APIURL, (okdata) => {
                        reloadSoundBank(APIURL);
                    }, (errdata) => {
                        alert("Error importing soundbank from XLSX: " + errdata.message);
                    });
                });
            } else {
                console.error("Error loading soundbank content:", xhr.status, xhr.statusText);
            }
        });

    })
    $('#messagebanklink').click(() => {
        sidemenu.hide();
        $('#content').load('messagebank.html', function (response, status, xhr) {
            if (status === "success") {
                console.log("Messagebank content loaded successfully");
                // initialize first state of buttons and text input
                $('#messagebanktablebody').empty();
                selectedmessagerow = null;
                let $btnClear = $('#btnClear');
                let $btnAdd = $('#btnAdd');
                let $btnRemove = $('#btnRemove');
                let $btnEdit = $('#btnEdit');
                let $btnExport = $('#btnExport');
                let $btnImport = $('#btnImport');
                $btnRemove.prop('disabled', true);
                $btnEdit.prop('disabled', true);
                let APIURL = "MessageBank/";


                reloadMessageBank(APIURL);
                $btnClear.click(() => {
                    if (confirm(`Are you sure want to clear Messagebank ? This procedure is not reversible`)) {
                        fetchAPI(APIURL + "List", "DELETE", {}, null, (okdata) => {
                            alert("Success clear messagebank" + okdata.message);
                            messagebankdata = []
                            selectedmessagerow = null;
                            fill_messagebanktablebody(messagebankdata);
                        }, (errdata) => {
                            alert("Error clear messagebank: " + errdata.message);
                        });
                    }
                });
                $btnAdd.click(() => {
                    let $modal = $('#messagebankmodal');
                    $modal.modal('show');
                    $modal.off('click.messagebanksave').on('click.messagebanksave', '#messagebanksave', function () {
                        const index = $('#messageindex').val();
                        const description = $('#messagedescription').val();
                        const language = $('#messagelanguage').val();
                        const ann_id = parseInt($('#messageannid').val());
                        const voice_type = $('#messagevoicetype').val();


                        $modal.modal('hide');
                    });
                    $modal.off('click.messagebankclose').on('click.messagebankclose', '#messagebankclose', function () {
                        $modal.modal('hide');
                    });
                });
                $btnRemove.click(() => {
                    if (selectedmessagerow) {
                        let cells = selectedmessagerow.find('td');
                        /** @type {MessageBank} */
                        let mb = {
                            index: cells.eq(0).text(),
                            description: cells.eq(1).text(),
                            language: cells.eq(2).text(),
                            aNN_ID: parseInt(cells.eq(3).text()),
                            voice_Type: cells.eq(4).text(),
                            message_Detail: cells.eq(5).text(),
                            message_TAGS: cells.eq(6).text()
                        }

                        if (confirm(`Are you sure to delete messagebank [${mb.index}] Description=${mb.description}? ANN_ID=${mb.aNN_ID} Language=${mb.language} Voice_Type=${mb.voice_Type} `)) {
                            fetchAPI(APIURL + "DeleteByIndex/" + mb.index, "DELETE", {}, null, (okdata) => {
                                alert("Success delete messagebank" + okdata.message);
                                messagebankdata = messagebankdata.filter(item => item.index !== mb.index);
                                selectedmessagerow = null;
                                fill_messagebanktablebody(messagebankdata);
                            }, (errdata) => {
                                alert("Error delete messagebank: " + errdata.message);
                            });
                        }
                    }
                });
                $btnEdit.click(() => {
                    if (selectedmessagerow) {
                        let cells = selectedmessagerow.find('td');
                        /** @type {MessageBank} */
                        let mb = {
                            index: cells.eq(0).text(),
                            description: cells.eq(1).text(),
                            language: cells.eq(2).text(),
                            aNN_ID: parseInt(cells.eq(3).text()),
                            voice_Type: cells.eq(4).text(),
                            message_Detail: cells.eq(5).text(),
                            message_TAGS: cells.eq(6).text()
                        }
                        if (confirm(`Are you sure to edit messagebank [${mb.index}] Description=${mb.description} ANN_ID=${mb.aNN_ID} Language=${mb.language} Voice_Type=${mb.voice_Type} `)) {
                            //TODO send edit command
                        }
                    }
                });
                $btnExport.click(() => {
                    DoExport(APIURL, "messagebank.xlsx");
                });
                $btnImport.click(() => {
                    DoImport(APIURL, (okdata) => {
                        reloadMessageBank(APIURL);
                    }, (errdata) => {
                        alert("Error importing messagebank from XLSX: " + errdata.message);
                    });
                });
            } else {
                console.error("Error loading messagebank content:", xhr.status, xhr.statusText);
            }
        });

    })
    $('#languagelink').click(() => {
        sidemenu.hide();
        $('#content').load('language.html', function (response, status, xhr) {
            if (status === "success") {
                console.log("Language content loaded successfully");
                // initialize first state of buttons and text input
                $('#languagebanktablebody').empty();
                selectedlanguagerow = null;
                let $btnClear = $('#btnClear');
                let $btnAdd = $('#btnAdd');
                let $btnRemove = $('#btnRemove');
                let $btnEdit = $('#btnEdit');
                let $btnExport = $('#btnExport');
                let $btnImport = $('#btnImport');
                $btnRemove.prop('disabled', true);
                $btnEdit.prop('disabled', true);
                let APIURL = "LanguageBank/";



                reloadLanguageBank(APIURL);
                $btnClear.click(() => {
                    if (confirm(`Are you sure want to clear Languagebank ? This procedure is not reversible`)) {
                        fetchAPI(APIURL + "List", "DELETE", {}, null, (okdata) => {
                            alert("Success clear languagebank" + okdata.message);
                            languagebankdata = []
                            selectedlanguagerow = null;
                            fill_languagebanktablebody(languagebankdata);
                        }, (errdata) => {
                            alert("Error clear languagebank: " + errdata.message);
                        });
                    }
                });
                $btnAdd.click(() => {
                    // show modal with id 'languagemodal'
                    let $modal = $('#languagemodal');
                    $modal.modal('show');
                    // save button click event
                    $modal.off('click.languagelinksave').on('click.languagelinksave', '#languagelinksave', function () {
                        const tag = $('#languagelinktag').val();
                        const langs = [];
                        if ($('#langID').is(':checked')) langs.push('INDONESIA');
                        if ($('#langLocal').is(':checked')) langs.push('LOCAL');
                        if ($('#langEN').is(':checked')) langs.push('ENGLISH');
                        if ($('#langARB').is(':checked')) langs.push('ARABIC');
                        if ($('#langJAP').is(':checked')) langs.push('JAPANESE');
                        if ($('#langCHI').is(':checked')) langs.push('CHINESE');

                        if (tag.length === 0) {
                            alert("Tag cannot be empty");
                            return;
                        }
                        if (langs.length === 0) {
                            alert("At least one language must be selected");
                            return;
                        }

                        const langString = langs.join(';');
                        let ll = {
                            tag: tag,
                            language: langString
                        }
                        fetchAPI(APIURL + "Add", "POST", {}, ll, (okdata) => {
                            alert("Success add language" + okdata.message);
                            reloadLanguageBank(APIURL);
                        }, (errdata) => {
                            alert("Error add language: " + errdata.message);
                        });
                        $modal.modal('hide');


                    });
                    // close button click event
                    $modal.off('click.languagelinkclose').on('click.languagelinkclose', '#languagelinkclose', function () {
                        $modal.modal('hide');
                    });
                });
                $btnRemove.click(() => {
                    if (selectedlanguagerow) {
                        let cells = selectedlanguagerow.find('td');
                        /** @type {Language} */
                        let ll = {
                            index: cells.eq(0).text(),
                            tag: cells.eq(1).text(),
                            language: cells.eq(2).text()
                        }
                        if (confirm(`Are you sure to delete language [${ll.index}] Tag=${ll.tag} Language=${ll.language}?`)) {
                            fetchAPI(APIURL + "DeleteByIndex/" + ll.index, "DELETE", {}, null, (okdata) => {
                                alert("Success delete language" + okdata.message);
                                languagebankdata = languagebankdata.filter(item => item.index !== ll.index);
                                selectedlanguagerow = null;
                                fill_languagebanktablebody(languagebankdata);
                            }, (errdata) => {
                                alert("Error delete language: " + errdata.message);
                            });
                        }
                    }
                });
                $btnEdit.click(() => {
                    if (selectedlanguagerow) {
                        let cells = selectedlanguagerow.find('td');
                        /** @type {Language} */
                        let ll = {
                            index: cells.eq(0).text(),
                            tag: cells.eq(1).text(),
                            language: cells.eq(2).text()
                        }
                        if (confirm(`Are you sure to edit language [${ll.index}] Tag=${ll.tag} Language=${ll.language}?`)) {
                            let $modal = $('#languagemodal');
                            $modal.find('#languagelinkindex').val(ll.index);
                            $modal.find('#languagelinktag').val(ll.tag);
                            let langs = ll.language.split(';');
                            $modal.find('#langID').prop('checked', langs.includes('INDONESIA'));
                            $modal.find('#langLocal').prop('checked', langs.includes('LOCAL'));
                            $modal.find('#langEN').prop('checked', langs.includes('ENGLISH'));
                            $modal.find('#langARB').prop('checked', langs.includes('ARABIC'));
                            $modal.find('#langJAP').prop('checked', langs.includes('JAPANESE'));
                            $modal.find('#langCHI').prop('checked', langs.includes('CHINESE'));
                            $modal.modal('show');
                            // save button click event
                            $modal.off('click.languagelinksave').on('click.languagelinksave', '#languagelinksave', function () {
                                const tag = $('#languagelinktag').val();
                                const langs = [];
                                if ($('#langID').is(':checked')) langs.push('INDONESIA');
                                if ($('#langLocal').is(':checked')) langs.push('LOCAL');
                                if ($('#langEN').is(':checked')) langs.push('ENGLISH');
                                if ($('#langARB').is(':checked')) langs.push('ARABIC');
                                if ($('#langJAP').is(':checked')) langs.push('JAPANESE');
                                if ($('#langCHI').is(':checked')) langs.push('CHINESE');
                                if (tag.length === 0) {
                                    alert("Tag cannot be empty");
                                    return;
                                }
                                if (langs.length === 0) {
                                    alert("At least one language must be selected");
                                    return;
                                }
                                const langString = langs.join(';');
                                if (ll.tag === tag && ll.language === langString) {
                                    alert("No changes detected");
                                    $modal.modal('hide');
                                    return;
                                }

                                ll.tag = tag;
                                ll.language = langString;
                                fetchAPI(APIURL + "UpdateByIndex/" + ll.index, "PATCH", {}, ll, (okdata) => {
                                    alert("Success edit language" + okdata.message);
                                    reloadLanguageBank(APIURL);
                                }, (errdata) => {
                                    alert("Error edit language: " + errdata.message);
                                });

                                $modal.modal('hide');
                            });
                            // close button click event
                            $modal.off('click.languagelinkclose').on('click.languagelinkclose', '#languagelinkclose', function () {
                                $modal.modal('hide');
                            });


                        }
                    }
                });
                $btnExport.click(() => {
                    DoExport(APIURL, "languagebank.xlsx");

                });
                $btnImport.click(() => {
                    DoImport(APIURL, (okdata) => {
                        reloadLanguageBank(APIURL);
                    }, (errdata) => {
                        alert("Error importing languagebank from XLSX: " + errdata.message);
                    });

                });
            } else {
                console.error("Error loading language content:", xhr.status, xhr.statusText);
            }
        });
    })
    $('#timerlink').click(() => {
        sidemenu.hide();
        $('#content').load('timer.html', function (response, status, xhr) {
            if (status === "success") {
                console.log("Timer content loaded successfully");
                // initialize first state of buttons and text input
                $('#schedulebanktablebody').empty();
                selectedschedulerow = null;
                let $btnClear = $('#btnClear');
                let $btnAdd = $('#btnAdd');
                let $btnEdit = $('#btnEdit');
                let $btnRemove = $('#btnRemove');
                let $btnExport = $('#btnExport');
                let $btnImport = $('#btnImport');
                $btnEdit.prop('disabled', true);
                $btnRemove.prop('disabled', true);
                let APIURL = "ScheduleBank/";


                reloadTimerBank(APIURL);
                $btnClear.click(() => {
                    if (confirm(`Are you sure want to clear Timerbank ? This procedure is not reversible`)) {
                        fetchAPI(APIURL + "List", "DELETE", {}, null, (okdata) => {
                            alert("Success clear schedulebank" + okdata.message);
                            schedulebankdata = []
                            selectedschedulerow = null;
                            fill_schedulebanktablebody(schedulebankdata);
                        }, (errdata) => {
                            alert("Error clear schedulebank: " + errdata.message);
                        });
                    }
                });
                $btnAdd.click(() => {
                    //TODO form add timer
                });
                $btnRemove.click(() => {
                    if (selectedtimerow) {
                        let cells = selectedtimerow.find('td');
                        /** @type {ScheduleBank} */
                        let sr = {
                            index: cells.eq(0).text(),
                            description: cells.eq(1).text(),
                            day: cells.eq(2).text(),
                            time: cells.eq(3).text(),
                            soundpath: cells.eq(4).text(),
                            repeat: cells.eq(5).text(),
                            enable: cells.eq(6).text(),
                            broadcastZones: cells.eq(7).text(),
                            language: cells.eq(8).text()
                        }
                        if (confirm(`Are you sure to delete schedule [${sr.index}] Description=${sr.description}?`)) {
                            fetchAPI(APIURL + "DeleteByIndex/" + sr.index, "DELETE", {}, null, (okdata) => {
                                alert("Success delete schedule" + okdata.message);
                                schedulebankdata = schedulebankdata.filter(item => item.index !== sr.index);
                                selectedtimerow = null;
                                fill_schedulebanktablebody(schedulebankdata);
                            }, (errdata) => {
                                alert("Error delete schedule: " + errdata.message);
                            });
                        }
                    }
                });
                $btnEdit.click(() => {
                    if (selectedtimerow) {
                        let cells = selectedtimerow.find('td');
                        /** @type {ScheduleBank} */
                        let sr = {
                            index: cells.eq(0).text(),
                            description: cells.eq(1).text(),
                            day: cells.eq(2).text(),
                            time: cells.eq(3).text(),
                            soundpath: cells.eq(4).text(),
                            repeat: cells.eq(5).text(),
                            enable: cells.eq(6).text(),
                            broadcastZones: cells.eq(7).text(),
                            language: cells.eq(8).text()
                        }
                        if (confirm(`Are you sure to edit schedule [${sr.index}] Description=${sr.description}?`)) {
                            //TODO send edit command
                        }
                    }
                });
                $btnExport.click(() => {
                    DoExport(APIURL, "schedulebank.xlsx");
                });
                $btnImport.click(() => {
                    DoImport(APIURL, (okdata) => {
                        reloadTimerBank(APIURL);
                    }, (errdata) => {
                        alert("Error importing schedulebank from XLSX: " + errdata.message);
                    });
                });
            } else {
                console.error("Error loading timer content:", xhr.status, xhr.statusText);
            }
        });
    })
    $('#loglink').click(() => {
        sidemenu.hide();
        $('#content').load('log.html', function (response, status, xhr) {
            if (status === "success") {
                console.log("Log content loaded successfully");
                const $logdate = $('#logdate');
                const $searchfilter = $('#searchfilter');
                let selectedlogdate = "";
                let logfilter = "";
                let APIURL = "/api/Logs/";


                if (!$logdate.val()) {
                    const today = new Date();
                    const dd = String(today.getDate()).padStart(2, '0');
                    const mm = String(today.getMonth() + 1).padStart(2, '0');
                    const yyyy = today.getFullYear();
                    $logdate.val(`${yyyy}-${mm}-${dd}`);
                    selectedlogdate = `${dd}/${mm}/${yyyy}`;
                }
                $logdate.off('change').on('change', function () {
                    const selected = $(this).val();
                    if (selected) {
                        const [year, month, day] = selected.split('-');
                        selectedlogdate = `${day}/${month}/${year}`;
                        reloadLogs(APIURL, selectedlogdate, logfilter);
                    }
                });

                $searchfilter.off('input').on('input', function () {
                    logfilter = $(this).val();
                    reloadLogs(APIURL, selectedlogdate, logfilter);
                });

            } else {
                console.error("Error loading log content:", xhr.status, xhr.statusText);
            }
        });
    })
    $('#settinglink').click(() => {
        sidemenu.hide();
        $('#content').load('setting.html', function (response, status, xhr) {
            if (status === "success") {
                console.log("Setting content loaded successfully");
                //sendCommand("getSetting", "");
            } else {
                console.error("Error loading setting content:", xhr.status, xhr.statusText);
            }
        });
    })
    $('#logoutlink').click(() => {
        window.location.href = "login.html"
    })


    /**
     * Create log Request Data
     * @param {String} logdate in format dd/mm/yyyy
     * @param {String} logfilter 
     * @returns JSON string of log Request data
     */
    function logRequstData(logdate, logfilter) {
        if (logdate && logdate.length > 0) {
            const dateRegex = /^(0[1-9]|[12][0-9]|3[01])\/(0[1-9]|1[0-2])\/\d{4}$/;
            if (dateRegex.test(logdate)) {
                // logdate is valid
                return JSON.stringify({
                    date: logdate,
                    filter: logfilter
                })
            }

        }
        return ""
    }
});