/**
 * Global type definition.
 * @typedef {Object}  feWpOrders    - Array of localization strings.
 * @property {string} root          - URL.
 * @property {string} nonce         - REST nonce.
 * @property {string} admin_api_key - 16 byte random string.
 * @property {string} timepout      - Fetch timeout error message.
 * @property {string} no_route      - The server does not support this request; please ask your site administrator for help.
 * @property {string} fetch_failed  - Could not connect to the server; please ask your site administrator for help.
 * @property {string} forbidden     - You do not have permission on the server to execute this request; please ask your site administrator for help.
 * @property {string} invalid_json  - The server did not return valid JSON:
 */

(function () {

    const FE_TIMEOUT = 5000;

    /**
     * Generate 16 byte random string.
     *
     * @returns {string} Generated random string.
     */
    function randomString() {
        const chars ='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
        const randomValues = new Uint32Array(16);
        crypto.getRandomValues(randomValues);

        let result = '';
        for (let i = 0; i < 16; i++) {
            result += chars.charAt(randomValues[i] % chars.length);
        }
        return result;
    }


    /**
     * Toggles UI state while a fetch is pending.
     *
     * @param {HTMLButtonElement}  feButton
     * @param {boolean}            active  true → show spinner, hide cursor, disable button
     */
    function setLoadingState(feButton, active) {
        document.body.style.cursor = active ? 'wait' : 'default';
        feButton.disabled = active;
        feButton.style.opacity = active ? '0.6' : '1';
    }


    /**
     * Show detailed translated error message.
     *
     * @param {Object} feError Can be a JavaScript Error object or a WP_Error object.
     */
    function showDetailedError(feError) {
        if (feError instanceof Error) {
            console.error(feError.name + ': ' + feError.message);
            if (feError.name === 'TimeoutError') {
                fastEventShowSettingsAlarm(feWpOrders.timeout, 'alert-danger');
            } else if (feError.name === 'TypeError' && feError.message === 'Failed to fetch') {
                fastEventShowSettingsAlarm(feWpOrders.fetch_failed, 'alert-danger');
            } else if (feError.name === 'SyntaxError' && feError.message.startsWith('Unexpected token')) {
                fastEventShowSettingsAlarm(feWpOrders.invalid_json + feError.message, 'alert-danger');
            } else {
                fastEventShowSettingsAlarm(feError.message, 'alert-danger');
            }
        } else {
            if ('code' in feError) {
                console.error(feError.code + ': ' + feError.message);
                if (feError.code === 'rest_no_route') {
                    fastEventShowSettingsAlarm(feWpOrders.no_route, 'alert-danger');
                } else if (feError.code === 'rest_forbidden') {
                    fastEventShowSettingsAlarm(feWpOrders.forbidden, 'alert-danger');
                } else {
                    fastEventShowSettingsAlarm(feError.message, 'alert-danger');
                }
            } else {
                console.error(feError.message);
                fastEventShowSettingsAlarm(feError.message, 'alert-danger');
            }
        }
    }


    /**
     * Show alert at the top of the screen.
     * @param {string}  msg  - Message to show.
     * @param {string}  type - Alert class.
     */
    function fastEventShowSettingsAlarm(msg, type) {
        document.getElementById('fe-alert-content-settings').innerHTML = msg;
        const feSettings = document.getElementById('fe-alert-settings');
        feSettings.classList.remove('alert-danger', 'alert-success', 'd-none');
        feSettings.classList.add(type, 'show');
    }

    // Listen for the built‑in dismissed event, then just hide
    document.getElementById('fe-alert-settings').addEventListener('close.bs.alert', function (e) {
        e.preventDefault();
        this.classList.add('d-none');
    });

    /**
     * Install the web interface
     * @param {HTMLButtonElement}  button  - Button click event.
     * @param {MouseEvent}         ev      - Mouse event.
     * @type {HTMLElement}
     */
    function installWebInterface(button, ev) {
        ev.preventDefault();

        setLoadingState(button,true);
        fetch(feWpOrders.root + 'settings/mgt', {
            method: 'POST',
            signal: AbortSignal.timeout(FE_TIMEOUT),
            headers: {
                'X-WP-Nonce': feWpOrders.nonce,
                'X-FE-API-Key': feWpOrders.admin_api_key,
            }
        })
            .then(async response => {
                if (response.ok) {
                    window.location.reload();
                } else {
                    showDetailedError(await response.json());
                }
            })
            .catch(error => showDetailedError(error))
            .finally(function () {
                setLoadingState(button,false);
            })
    }


    // Return to the previous tab
    const previousTab = localStorage.getItem('FastEventsSettingsTab');
    if (previousTab !== null) {
        if (document.getElementById(previousTab)) {
            document.getElementById(previousTab).click();
        }
    }


    // Generate config qrcode for the FE Admin App
    let feAdminKey = document.getElementById('fe_admin_api_key');
    let feAdminHome = document.getElementById('fe_admin_api_home_url').innerText;

    // Generate config qrcode for FE Admin from a key
    let qrcode = new QRCode(document.getElementById('fe_admin_api_qrcode'), 'fe_config|' + feAdminHome + '|' + feAdminKey.value);

    document.getElementById('fe_admin_api_key_button').onclick = function (ev) {
        ev.preventDefault();

        // Create a new key for FE Admins
        feAdminKey.value = randomString();
        qrcode.clear();
        qrcode.makeCode('fe_config|' + feAdminHome + '|' + feAdminKey.value);
    }


    /**
     * Save the settings
     * @param ev
     * @returns {Promise<void>}
     */
    document.getElementById('fe-settings-form-save').onclick = async function (ev) {
        ev.preventDefault();
        try {
            setLoadingState(this,true);
            let response = await fetch(feWpOrders.root + 'settings', {
                method: 'POST',
                signal: AbortSignal.timeout(FE_TIMEOUT),
                body: new FormData(document.getElementById('fe-settings-form')),
                headers: {
                    'X-WP-Nonce': feWpOrders.nonce,
                    'X-FE-API-Key': feWpOrders.admin_api_key,
                }
            })
            const json = await response.json();
            if (response.ok) {
                // If the status = 201, redo the request to install the new Payment Provider
                if (response.status === 201) {
                    try {
                        let response = await fetch(feWpOrders.root + 'settings', {
                            method: 'POST',
                            signal: AbortSignal.timeout(FE_TIMEOUT),
                            body: new FormData(document.getElementById('fe-settings-form')),
                            headers: {
                                'X-WP-Nonce': feWpOrders.nonce,
                                'X-FE-API-Key': feWpOrders.admin_api_key,
                            }
                        })
                        const json = await response.json();
                        if (response.ok) {
                            fastEventShowSettingsAlarm(json, 'alert-success');
                            setTimeout(() => {
                                location.reload(true);
                            }, 1500);
                        } else {
                            showDetailedError(json);
                        }
                    } catch (e) {
                        showDetailedError(e);
                    } finally {
                        setLoadingState(this, false);
                    }
                }
                fastEventShowSettingsAlarm(json, 'alert-success');
                setTimeout(() => {
                    location.reload(true);
                }, 1500);
            } else {
                showDetailedError(json);
            }
        } catch (e) {
            showDetailedError(e);
        } finally {
            setLoadingState(this, false);
        }
    }

    /**
     * Reset the Action Scheduler clean cache job
     * @param ev
     * @returns {Promise<void>}
     */
    document.getElementById('fe-settings-as-reset').onclick = async function (ev) {
        ev.preventDefault();
        try {
            setLoadingState(this,true);
            let response = await fetch(feWpOrders.root + 'settings/as/reset', {
                method: 'GET',
                signal: AbortSignal.timeout(FE_TIMEOUT),
                headers: {
                    'X-WP-Nonce': feWpOrders.nonce,
                    'X-FE-API-Key': feWpOrders.admin_api_key,
                }
            })
            const json = await response.json();
            if (response.ok) {
                fastEventShowSettingsAlarm(json, 'alert-success');
            } else {
                showDetailedError(json);
            }
        } catch (e) {
            showDetailedError(e);
        } finally {
            setLoadingState(this,false);
        }
    }

    /**
     * Check whether the daily action-scheduler tasks of Fast Events are still running and, if necessary, restart them.
     * @param ev
     * @returns {Promise<void>}
     */
    document.getElementById('fe-settings-as-check').onclick = async function (ev) {
        ev.preventDefault();
        try {
            setLoadingState(this,true);
            let response = await fetch(feWpOrders.root + 'settings/as/check', {
                method: 'GET',
                signal: AbortSignal.timeout(FE_TIMEOUT),
                headers: {
                    'X-WP-Nonce': feWpOrders.nonce,
                    'X-FE-API-Key': feWpOrders.admin_api_key,
                }
            })
            const json = await response.json();
            if (response.ok) {
                fastEventShowSettingsAlarm(json, 'alert-success');
            } else {
                showDetailedError(json);
            }
        } catch (e) {
            showDetailedError(e);
        } finally {
            setLoadingState(this,false);
        }
    }

    /**
     * Install the Web interface
     * @type {HTMLElement}
     */
    const fe_install = document.getElementById('fe-admin-mgt-install');
    if (fe_install) {
        fe_install.onclick = async function (ev) {
            installWebInterface(this, ev);
        }
    }

    /**
     * Update the Web interface
     * @type {HTMLElement}
     */
    const fe_install_update = document.getElementById('fe-admin-mgt-install-update');
    if (fe_install_update) {
        fe_install_update.onclick = async function (ev) {
            installWebInterface(this, ev);
        }
    }

    /**
     * Update the Web interface via the 'Check for new version' dialog
     * @type {HTMLElement}
     */
    const fe_install_update_dialog = document.getElementById('fe-admin-mgt-install-update-dialog');
    if (fe_install_update_dialog) {
        fe_install_update_dialog.onclick = async function (ev) {
            installWebInterface(this, ev);
        }
    }

    /**
     * Check for a new Web interface version
     *
     * @typedef {Object}  json         - JSON content from REST API.
     * @property {string} new_version  - Name of the new version.
     * @property {string} new_changes  - Changes in this version.
     */
    const fe_check = document.getElementById('fe-admin-mgt-check');
    if (fe_check) {
        fe_check.onclick = async function (ev) {
            ev.preventDefault();
            try {
                setLoadingState(this,true);
                let response = await fetch(feWpOrders.root + 'settings/mgt', {
                    method: 'GET',
                    signal: AbortSignal.timeout(FE_TIMEOUT),
                    headers: {
                        'X-WP-Nonce': feWpOrders.nonce,
                        'X-FE-API-Key': feWpOrders.admin_api_key,
                    }
                })
                const json = await response.json();
                if (response.ok) {
                    if (json['update_available'] === false) {
                        fastEventShowSettingsAlarm(json['message'], 'alert-success');
                    } else {
                        const fe_version = document.getElementById('fe-admin-update-dialog-version');
                        const fe_changes = document.getElementById('fe-admin-update-dialog-changes');
                        fe_version.textContent = json.new_version;
                        fe_changes.textContent = json.new_changes;
                        const myModal = new bootstrap.Modal(document.getElementById('fe-admin-update-dialog'), {keyboard: false});
                        myModal.show();
                    }
                } else {
                    showDetailedError(json);
                }
            } catch (e) {
                showDetailedError(e);
            } finally {
                setLoadingState(this,false);
            }
        }
    }

    /**
     * Remove the Web interface
     * @type {HTMLElement}
     */
    const fe_remove = document.getElementById('fe-admin-mgt-remove');
    if (fe_remove) {
        fe_remove.onclick = async function (ev) {
            ev.preventDefault();
            try {
                setLoadingState(this,true);
                let response = await fetch(feWpOrders.root + 'settings/mgt', {
                    method: 'DELETE',
                    signal: AbortSignal.timeout(FE_TIMEOUT),
                    headers: {
                        'X-WP-Nonce': feWpOrders.nonce,
                        'X-FE-API-Key': feWpOrders.admin_api_key,
                    }
                })
                const json = await response.json();
                if (response.ok) {
                    window.location.reload();
                } else {
                    showDetailedError(json);
                }
            } catch (e) {
                showDetailedError(e);
            } finally {
                setLoadingState(this,false);
            }
        }
    }

    /**
     * Set/unset auto-update of the Web interface
     * @type {HTMLElement}
     */
    const fe_auto_update = document.getElementById('fe-admin-mgt-auto-update');
    if (fe_auto_update) {
        fe_auto_update.onclick = async function () {
            const fd = new FormData();
            fd.append('auto_update', document.getElementById('fe-admin-mgt-auto-update').checked);
            try {
                setLoadingState(this,true);
                let response = await fetch(feWpOrders.root + 'settings/mgt/auto-update', {
                    method: 'POST',
                    signal: AbortSignal.timeout(FE_TIMEOUT),
                    body: fd,
                    headers: {
                        'X-WP-Nonce': feWpOrders.nonce,
                        'X-FE-API-Key': feWpOrders.admin_api_key,
                    }
                })
                const json = await response.json();
                if (response.ok) {
                    fastEventShowSettingsAlarm(json, 'alert-success');
                } else {
                    showDetailedError(json);
                }
            } catch (e) {
                showDetailedError(e);
            } finally {
                setLoadingState(this,false);
            }
        }
    }

    /**
     * Save the last clicked tab where we return after a page refresh.
     * @param ev
     */
    const tabs = ['fe-pills-ppa-tab', 'fe-pills-email-tab', 'fe-pills-rcap-tab', 'fe-pills-admin-tab',
                           'fe-pills-aswh-tab', 'fe-pills-encrypt-tab', 'fe-pills-log-tab', 'fe-pills-misc-tab', 'fe-pills-mgt-tab'];
    tabs.forEach(function(tab) {
        if (document.getElementById(tab)) {
            document.getElementById(tab).onclick = function() {
                localStorage.setItem('FastEventsSettingsTab', this.id);
            }
        }
    });
})();