"use strict";
import { showAlert } from './alerts.js';
// import Scenari from './scenari.js';
import Api from "./mqtt/api.js";
import Sensori from './sensori.js';

class Antifurto {
    static attivaAntifurtoINbtn = null;
    static sensoriMovimento = [];
    static outputSuono = null;
    static outputAntifurtoStato = null;
    /**
     * the div where everything related to the AntiFurto is stored
     */
    static antifurtoContainer = document.getElementById('antifurtoContainer');
    /**
     * the progress bar used to show the user how much is left until the alarm is triggered
     */
    static progressBar = document.getElementById('antifurto-progress');
    /**
     * describes the current status of the progress bar
     */
    static currentPercentage = parseInt(Antifurto.progressBar.style.width);
    /**
     * shows if the antitheft is on or off
     */
    static status = false;
    /**
     * contains the user's preferences regarding when to trigger the alarm
     */
    static soglia = undefined;
    /**
     * shows if the alarm is on or off
     */
    static alarmStatus = false;

    static isScenariAvailable = null;
    static scenariClass = null;

    constructor(servicesArray) {
        Antifurto.isScenariAvailable = servicesArray[0];
        Api.fixedCallbackValoreAttenzione = Antifurto.setProgressBarFromServer;
        Api.fixedCallbackStatoAllarme = Antifurto.setAlarmFromServer;
        Antifurto.init(servicesArray);
    }

    static async init(servicesArray) {
        Antifurto.fillTable();

        const antifurtoBtn = document.getElementById('mainButtonContainer').children[2];
        antifurtoBtn.addEventListener('click', async () => {
            if(servicesArray[0]){
                try{
                    Antifurto.scenariClass.toggleContainer(false);
                } catch (error) {
                    if(error.message !== "Scenari.toggleContainer is not a function" && error.message !== "Cannot read properties of null (reading 'classList')")
                    throw error;
                }
            }
            if(servicesArray[1]){
                try {
                    const luci = await import('./luci.js');
                    luci.default.toggleContainer(false);
                } catch (error) {
                    if(error.message !== "Luci.toggleContainer is not a function" && error.message !== "Cannot read properties of null (reading 'classList')")
                    throw error;
                }
            }
            Antifurto.toggleContainer(true);
        }, false);
        if(servicesArray[0]){
            const scenari = await import('./scenari.js');
            Antifurto.scenariClass = scenari.default;
        }

        Antifurto.antifurtoBtnListener();
    }
    /**
     * sets up the progress bar to better accomodate the user's preferences
     * @param {number} soglia the integer value from which the alarm will be triggered
     */
    static setupSoglia(soglia, fromServer = false) {
        //HERE server send soglia
        if (soglia == null)
            return;
        if (fromServer) {
            Antifurto.showEditsSoglia(soglia, fromServer);
            return;
        }
        try {
            Api.setAntifurtoSoglia(soglia, fromServer);
        } catch (error) {
            if (error.error)
                showAlert('Errore', error.error, false);
            else if (error.message)
                showAlert('Errore', error.message, false);
        }
    }

    static showEditsSoglia(soglia, fromServer = false) {
        Antifurto.soglia = soglia;
        //the progress bar goes a little bit more than the soglia
        Antifurto.progressBar.setAttribute('aria-valuemax', Antifurto.maxProgressBar());
        // Antifurto.resetProgressBar(fromServer);
    }
    /**
     * edits and shows the modal to toggle the antitheft
     */
    static antifurtoBtnListener() {
        const antifurtoBtn = document.getElementById('antifurto-stato-antifurto');
        const modal = document.getElementById('toggle-antifurto-modal');
        const modalBody = modal.querySelector('.modal-body');
        const modalLauncher = document.getElementById('antifurto-modal-launcher');

        antifurtoBtn.addEventListener('click', () => {
            const children = modalBody.children;
            // p, p
            /*
            <p>Stai per abilitare l'antifurto.</p>
            <p>Vuoi continuare?</p>
            */
            if (antifurtoBtn.innerText === 'ON') {
                // the antitheft is on
                children[0].innerText = "Stai per disabilitare l'antifurto.";
                okBtn.innerText = 'Disattiva';
            } else {
                /*if (Antifurto.soglia === undefined) {
                    console.log('j');
                    showAlert('Soglia', "Non hai ancora impostato la soglia di sicurezza. Impostala prima di attivare l'antifurto", false);
                    return;
                }*/
                // the antitheft is off
                children[0].innerText = "Stai per abilitare l'antifurto.";
                okBtn.innerText = 'Attiva';
            }
            // launch the modal
            modalLauncher.click();
        }, false);

        const okBtn = modal.querySelector('#toggle-antifurto-btn');
        const closeModal = modal.querySelector('.btn.btn-danger');
        okBtn.addEventListener('click', () => {
            // close the modal
            closeModal.click();
            // toggle the antitheft
            const activating = antifurtoBtn.innerText === 'OFF';
            Antifurto.activate(activating);
        }, false);
    }
    /**
     * function to activate or deactivate the antitheft and syncronize the button in the scenari
     * @param {Boolean} newStatus whether to activate or deactivate the antitheft
     * @param {Boolean} fromScenari usually false or undefined; true only if the function is called from the scenari
     */
    static activate(newStatus, fromScenari = false, fromServer = false) {
        if(Antifurto.attivaAntifurtoINbtn != null && Antifurto.isScenariAvailable && Antifurto.scenariClass.antifurtoINbtn != null && Antifurto.attivaAntifurtoINbtn !== Antifurto.scenariClass.antifurtoINbtn) {
            try{
                Antifurto.scenariClass.updateINbtnAntifurto(Antifurto.attivaAntifurtoINbtn);
            } catch (error) {
                if(error.message !== "Scenari.updateINbtn is not a function")
                    throw error;
            }
        }
        if (newStatus === Antifurto.status)
            return;
        let scenariPresent = false;
        if (fromScenari === false && Antifurto.isScenariAvailable) {//ridondanza necessaria nel caso in cui antifurto non sia attivo
            try{
                Antifurto.scenariClass.correctlySetAntifurto(newStatus, true, fromServer);
                scenariPresent = true;
            } catch (error){
                if(error.message !== "Scenari.correctlySetAntifurto is not a function")
                    throw error;
            }
            // return;
        }
        const previousStatus = Antifurto.status;
        if (fromServer || scenariPresent) {
            Antifurto.showChangeAntifurtoStatus(previousStatus, newStatus, fromScenari, fromServer);
            return;
        }
        // HERE ok server set the status of the antitheft
        Api.setAntifurtoStatus({ previousStatus, fromScenari, fromServer });
    }

    static showChangeAntifurtoStatus(previousStatus, newStatus, fromScenari = false, fromServer = false) {
        // if (fromScenari === false) {//ridondanza necessaria nel caso in cui antifurto non sia attivo
        //     Scenari.correctlySetAntifurto(newStatus, true, fromServer);
        //     // return;
        // }
        const antifurtoBtn1 = document.getElementById('antifurto-stato-antifurto');
        const antifurtoBtn2 = document.getElementById('scenari-stato-antifurto');
        if(newStatus === previousStatus)
            return;
        if (newStatus) {
            if(antifurtoBtn1.innerText === 'ON' && antifurtoBtn2.innerText === 'ON')
                return;
            antifurtoBtn1.innerText = 'ON';
            antifurtoBtn1.classList.remove('btn-danger');
            antifurtoBtn1.classList.add('btn-success');
            antifurtoBtn2.innerText = 'ON';
            antifurtoBtn2.classList.remove('btn-danger');
            antifurtoBtn2.classList.add('btn-success');
        } else {
            if(antifurtoBtn1.innerText === 'OFF' && antifurtoBtn2.innerText === 'OFF')
                return;
            antifurtoBtn1.innerText = 'OFF';
            antifurtoBtn1.classList.remove('btn-success');
            antifurtoBtn1.classList.add('btn-danger');
            antifurtoBtn2.innerText = 'OFF';
            antifurtoBtn2.classList.remove('btn-success');
            antifurtoBtn2.classList.add('btn-danger');
            Antifurto.activateAlarm(false);
            Antifurto.resetProgressBar(fromServer);
        }
        Antifurto.status = newStatus;
    }

    static setAlarmFromServer(newStatus) {
        Antifurto.activateAlarm(newStatus, true);
    }
    /**
     * toggles the bell if the alarm is on
     * @param {Boolean} activating if true, the bell will turn on
     */
    static activateAlarm(activating, fromServer = false) {
        // if the antitheft is off, the bell shouldn't turn on
        // if the alarmStatus is already set, nothing else should be done
        if (Antifurto.status === false || Antifurto.alarmStatus === activating)
            return;
        // if (fromServer)
            Antifurto.showChangeAlarmStatus(activating, fromServer);
        // else
        //     Antifurto.sendAlarmStatusServer(activating, fromServer);
    }

    // static async sendAlarmStatusServer(activating, fromServer = false) {
    //     try {
    //         const resp = await Api.setAntifurtoAllarme({ stato: activating });
    //         if (await resp == null)
    //             Antifurto.showChangeAlarmStatus(activating, fromServer);
    //     } catch (error) {
    //         if (error.error)
    //             showAlert('Errore', error.error, false);
    //         else if (error.message)
    //             showAlert('Errore', error.message, false);
    //     }
    // }

    static showChangeAlarmStatus(activating, fromServer = false) {
        Antifurto.alarmStatus = activating;
        const bell = document.getElementById('antifurto-bell');
        activating ? bell.classList.add('fa-shake') : bell.classList.remove('fa-shake');
    }
    /**
     * inputs a delta and takes care of updating the progress bar and the server
     * @param {number} percentage the percentage to add to the progress bar (+/-)
     */
    static changeProgressBar(percentage, fromServer = false) {
        // if the antitheft is turned off, the progress bar shouldn't change
        if (!Antifurto.status && !fromServer) {
            showAlert('Antifurto', "L'antifurto รจ spento", false);
            return;
        }
        /*if (Antifurto.soglia == null && !fromServer) {
            console.log('j');
            showAlert('Soglia', "Non hai ancora impostato la soglia di sicurezza. Impostala prima di attivare l'antifurto", false);
            return;
        }*/
        const oldPercentage = Antifurto.currentPercentage;
        let newPercentage = Math.floor(oldPercentage + percentage);
        const maxProgressAvailable = Antifurto.maxProgressBar();
        if (newPercentage > maxProgressAvailable)
            newPercentage = maxProgressAvailable;
        if (newPercentage < 0)
            newPercentage = 0;
        if (oldPercentage === newPercentage && newPercentage === maxProgressAvailable) {
            showAlert('Antifurto', "Massimo valore raggiunto!", false);
            return;
        }
        // HERE server send the new percentage
        if (!fromServer)
            Antifurto.sendServerPercentage(newPercentage);
        else
            Antifurto.showChangeProgressBar(newPercentage, fromServer);
    }

    static setProgressBarFromServer(percentage) {
        Antifurto.changeProgressBar(percentage - Antifurto.currentPercentage, true);
    }

    static sendServerPercentage(percentage) {
        try {
            Api.setAntifurtoAttenzione(percentage);
            // if (await resp == null)
            //     Antifurto.showChangeProgressBar(percentage);
        } catch (error) {
            if (error.error)
                showAlert('Errore', error.error, false);
            else if (error.message)
                showAlert('Errore', error.message, false);
        }
    }

    static showChangeProgressBar(newPercentage, fromServer = false) {
        Antifurto.progressBar.style.width = newPercentage + '%';
        Antifurto.progressBar.setAttribute('aria-valuenow', newPercentage.toString());
        Antifurto.progressBar.innerHTML = newPercentage + '%';
        Antifurto.currentPercentage = newPercentage;
        // check if the soglia is reached
        Antifurto.activateAlarm(newPercentage >= Antifurto.soglia, fromServer);
        const quarterSoglia = Antifurto.soglia / 4;
        // change colors of the progress bar
        if (newPercentage <= quarterSoglia) {
            if (Antifurto.progressBar.classList.contains('bg-info'))
                return;
            Antifurto.progressBar.classList.add('bg-info');
            Antifurto.progressBar.classList.remove('bg-success');
            Antifurto.progressBar.classList.remove('bg-warning');
            Antifurto.progressBar.classList.remove('bg-danger');
        } else if (newPercentage <= 2 * quarterSoglia) {
            if (Antifurto.progressBar.classList.contains('bg-success'))
                return;
            Antifurto.progressBar.classList.remove('bg-info');
            Antifurto.progressBar.classList.add('bg-success');
            Antifurto.progressBar.classList.remove('bg-warning');
            Antifurto.progressBar.classList.remove('bg-danger');
        } else if (newPercentage <= 3 * quarterSoglia) {
            if (Antifurto.progressBar.classList.contains('bg-warning'))
                return;
            Antifurto.progressBar.classList.remove('bg-info');
            Antifurto.progressBar.classList.remove('bg-success');
            Antifurto.progressBar.classList.add('bg-warning');
            Antifurto.progressBar.classList.remove('bg-danger');
        } else {
            if (Antifurto.progressBar.classList.contains('bg-danger'))
                return;
            Antifurto.progressBar.classList.remove('bg-info');
            Antifurto.progressBar.classList.remove('bg-success');
            Antifurto.progressBar.classList.remove('bg-warning');
            Antifurto.progressBar.classList.add('bg-danger');
        }
    }
    /**
     * resets the progress bar to 0
     */
    static resetProgressBar(fromServer = false) {
        Antifurto.changeProgressBar(-Antifurto.currentPercentage, fromServer);
    }
    /**
     * @returns the maximum value of the progress bar
     */
    static maxProgressBar() {
        if (Antifurto.soglia == null)
            return 100;
        const max = Antifurto.soglia + (Antifurto.soglia * 0.2);
        return max > 100 ? 100 : max;
    }
    /**
     * get all user's data from the server and show them in the table
     */
    static fillTable() {
        // HERE server get all sensors for the antitheft
        // HERE server get antitheft status
        // HERE server get soglia
        // HERE server get attenzione
        // HERE server get stato allarme
        try {
            if (!Api.isConnected) {
                setTimeout(() => Antifurto.fillTable(), 2500);
                return;
            }
            Api.getAntifurto();
        } catch (error) {
            if (error.error)
                showAlert('Errore', error.error, false);
            else if (error.message)
                showAlert('Errore', error.message, false);
        }
    }

    static mostraAntifurtoServer(datiVari) {
        if (Antifurto.attivaAntifurtoINbtn != null)
            return;
        /*
         {
         "stato": 0,
     +    "soglia": 50,
     +    "output-suono": "OUT0",
     +    "interruttore": "IN0",
     +    "output-antifurto": "OUT1",
     +    "valore-attuale": 0,
     +    "sensori-movimento": [
             "IN1",
             "IN2",
             "IN3"
         ],
     +    "allarme": false,
     +    "antifurto": false
         }
        */
        if (Antifurto.attivaAntifurtoINbtn == null) {
            const sensoreIN = datiVari.interruttore;
            const sin = Sensori.claimSensore(sensoreIN);
            if (sin != null || (Antifurto.isScenariAvailable && Antifurto.scenariClass?.antifurtoINbtn.nome === sensoreIN)) {


                Antifurto.attivaAntifurtoINbtn = (sin != null ? sin : (Antifurto.isScenariAvailable ? Antifurto.scenariClass.antifurtoINbtn : null));
                Antifurto.updateTooltipINbtnAntifurto();
                if (Antifurto.scenariClass?.antifurtoINbtn !== Antifurto.attivaAntifurtoINbtn) {
                    if (Antifurto.isScenariAvailable && Antifurto.attivaAntifurtoINbtn == null && Antifurto.scenariClass?.antifurtoINbtn != null) {
                        Antifurto.attivaAntifurtoINbtn = Antifurto.scenariClass.antifurtoINbtn;
                        Antifurto.scenariClass.updateINbtnAntifurto(Antifurto.attivaAntifurtoINbtn);
                    }
                }
            }
        }

        if (Antifurto.outputSuono == null) {
            const suonoOUT = datiVari["output-suono"];
            const sensSuonoOUT = Sensori.claimSensore(suonoOUT);
            if (sensSuonoOUT != null) {
                Antifurto.outputSuono = sensSuonoOUT;
                Antifurto.updateTooltipOUTbtnSuono();
            }
        }

        if (Antifurto.outputAntifurtoStato == null) {
            const sensoreOUT = datiVari["output-antifurto"];
            const sout = Sensori.claimSensore(sensoreOUT);
            if (sout != null) {
                Antifurto.outputAntifurtoStato = sout;
                Antifurto.updateTooltipOUTbtnAntifurto();
            }
        }


        Antifurto.setupSoglia(datiVari.soglia != null ? datiVari.soglia : null, true);//imposta currentPercentage a 0
        Antifurto.activate(datiVari.antifurto != null ? datiVari.antifurto : false, false, true);
        Antifurto.changeProgressBar(datiVari["valore-attuale"] != null ? datiVari["valore-attuale"] : 0, true);//imposta currentPercentage a valore-attuale o 0
        Antifurto.activateAlarm((datiVari.allarme != null ? datiVari.allarme : Antifurto.currentPercentage >= Antifurto.soglia), true);//HERE this true was from the bellClick
        const sensori = datiVari["sensori-movimento"];
        // TODO show all sensors in the table
        for (const sens of sensori) {
            const s = Sensori.claimSensore(sens);
            if (s != null) {
                s.utilizzo = `Sensore di movimento per l'antifurto [${s.nome.toUpperCase()}]`;
                Antifurto.sensoriMovimento.push(s);
                // Sensori.showSensore(s);
            }
        }

        Sensori.initializaTooltips();
    }

    static setTooltip(sensore) {
        const antifurtoBtn1 = document.getElementById('antifurto-stato-antifurto');
        const antifurtoBtn2 = document.getElementById('scenari-stato-antifurto');
        antifurtoBtn1.setAttribute('data-sensore-in', Antifurto.attivaAntifurtoINbtn);
        antifurtoBtn1.setAttribute('title', sensore.utilizzo);
        antifurtoBtn2.setAttribute('data-sensore-in', Antifurto.attivaAntifurtoINbtn);
        antifurtoBtn2.setAttribute('title', sensore.utilizzo);
        Sensori.initializaTooltips();
    }
    /**
     * toggle the visibility of the antifurto container
     * @param {Boolean} visible whether the container should be visible or not
     */
    static toggleContainer(visible) {
        if (visible) {
            Antifurto.antifurtoContainer.classList.remove('invisible');
        } else {
            Antifurto.antifurtoContainer.classList.add('invisible');
        }
    }

    static updateConfiguration(conf) {
        console.log(conf);
        if(conf == null) return;
        if(conf.outputSuono != null && conf.outputSuono != Antifurto.outputSuono) {
            Antifurto.updateOUTbtnAllarme(conf.outputSuono);
        }
        if(conf.interruttore != null && conf.interruttore != Antifurto.attivaAntifurtoINbtn) {
            Antifurto.updateINbtnAntifurto(conf.interruttore);
            if(Antifurto.isScenariAvailable)
                Antifurto.scenariClass.updateINbtnAntifurto(Antifurto.attivaAntifurtoINbtn);
        }
        if(conf.nomeOutputAntifurto != null && conf.nomeOutputAntifurto != Antifurto.outputAntifurtoStato) {
            Antifurto.updateOUTbtnAntifurto(conf.nomeOutputAntifurto);
            if(Antifurto.isScenariAvailable)
                Antifurto.scenariClass.updateOUTbtnAntifurto(Antifurto.outputAntifurtoStato);
        }

        Sensori.initializaTooltips();
    }

    static updateINbtnAntifurto(newINbtn){
        if(Antifurto.isScenariAvailable && Antifurto.attivaAntifurtoINbtn === Antifurto.scenariClass.antifurtoINbtn) return;
        if(Antifurto.attivaAntifurtoINbtn != null)
            Sensori.liberaSensore(Antifurto.attivaAntifurtoINbtn);

        if(newINbtn.nome == null){
            Antifurto.attivaAntifurtoINbtn = Sensori.claimSensore(newINbtn);
            Antifurto.updateTooltipINbtnAntifurto();
            return;
        }
        // sono stato chiamato dagli scenari
        Antifurto.attivaAntifurtoINbtn = newINbtn;
        // TODO server send new input
    }

    static updateOUTbtnAntifurto(newOUTbtn){//update the light for the antifurto status
        if(Antifurto.isScenariAvailable && Antifurto.outputAntifurtoStato === Antifurto.scenariClass.outputLuceAntifurto) return;
        if(Antifurto.outputAntifurtoStato != null)
            Sensori.liberaSensore(Antifurto.outputAntifurtoStato);

        if(newOUTbtn.nome == null){
            Antifurto.outputAntifurtoStato = Sensori.claimSensore(newOUTbtn);
            Antifurto.updateTooltipOUTbtnAntifurto();
            return;
        }
        // sono stato chiamato dagli scenari
        Antifurto.outputAntifurtoStato = newOUTbtn;
        // TODO server send new output
    }

    static updateOUTbtnAllarme(newOUTbtn){//update the light for the antifurto sound
        if(Antifurto.outputSuono != null)
            Sensori.liberaSensore(Antifurto.outputSuono);

        if(newOUTbtn.nome == null){
            Antifurto.outputSuono = Sensori.claimSensore(newOUTbtn);
            Antifurto.updateTooltipOUTbtnSuono();
            return;
        }
    }

    static updateTooltipINbtnAntifurto(){
        if(Antifurto.attivaAntifurtoINbtn == null) return;
        Antifurto.attivaAntifurtoINbtn.utilizzo = `Cambia stato dell'antifurto [${Antifurto.attivaAntifurtoINbtn.nome.toUpperCase()}]`;
        document.getElementById('attiva-antifurto-btn').setAttribute('title',Antifurto.attivaAntifurtoINbtn.utilizzo);
        document.getElementById('toggle-antifurto-btn').setAttribute('title',Antifurto.attivaAntifurtoINbtn.utilizzo);
    }

    static updateTooltipOUTbtnAntifurto(){
        if(Antifurto.outputAntifurtoStato == null) return;
        Antifurto.outputAntifurtoStato.utilizzo = `Stato dell'antifurto [${Antifurto.outputAntifurtoStato.nome.toUpperCase()}]`;
        document.getElementById('scenari-stato-antifurto').setAttribute('title', Antifurto.outputAntifurtoStato.utilizzo);
        document.getElementById('antifurto-stato-antifurto').setAttribute('title', Antifurto.outputAntifurtoStato.utilizzo);
    }

    static updateTooltipOUTbtnSuono(){
        if(Antifurto.outputSuono == null) return;
        Antifurto.outputSuono.utilizzo = `Suono dell'antifurto [${Antifurto.outputSuono.nome.toUpperCase()}]`;
        document.getElementById('antifurto-bell').setAttribute('title', Antifurto.outputSuono.utilizzo);
    }

    static updateSensoreConfiguration(sensore){
        Sensori.claimSensore(sensore["in"]);
    }
}

export default Antifurto;