"use strict";

import Luci from "../luci.js";
import ApiMqttIn from "./api-mqtt-in.js";
import ApiMqttOut from "./api-mqtt-out.js";

class Api {

    static isConnected = false;

    static baseURL = "/api/";
    // /api/luci/
    static callbackGetLuci = null;
    /**
     * gets the luci of the user from the server
     * @returns {*} all the lights of the user
     */
    static getLuci = callback => {
        Api.callbackGetLuci = callback;
        ApiMqttOut.getStatusLuci();
    };
    static sendLuciWeb = luci => {
        if( Api.callbackGetLuci == null)
            return;
        const callback = Api.callbackGetLuci;
        Api.callbackGetLuci = null;
        callback(luci);
    }

    static callbackGetAllLuci = null;
    static getAllLuci = callback => {
        if(callback == null)
            throw new Error("callback must be defined");
        Api.callbackGetAllLuci = callback;
        ApiMqttOut.getAllLuci();
    }
    static sendDataLuciWeb = luci => {
        if(Api.callbackGetAllLuci == null)
            return;
        const callback = Api.callbackGetAllLuci;
        Api.callbackGetAllLuci = null;
        callback(luci);
    }

    static luceMakeNewLuci = null;
    static callbackMakeNewLuci = null;
    /**
     * adds a new luce to the server
     * @param {luceTemplate} luce the luce to add to the server
     * @returns {*} null if the light was added
     */
    static makeNewLuci = (luce,callback) => {
        if (luce == null)
            throw new Error("luce must be defined");
        if(callback == null)
            throw new Error("callback must be defined");
        /*const url = Api.baseURL + "luci/";
        const response = await fetch(url, {
            method: "POST",
            headers: {
                "Content-Type": "application/json"
            },
            body: JSON.stringify(luce)
        });
        if (response.ok)
            return null;
        else
            throw await response.json();*/
        Api.luceMakeNewLuci = luce;
        Api.callbackMakeNewLuci = callback;
        ApiMqttOut.makeNewLuci(luce);
    }
    static sendWebNewLuci = luce => {
        if(Api.callbackMakeNewLuci == null)
            return;
        const oldLuce = Api.luceMakeNewLuci;
        if(oldLuce !== luce) {
            console.log('le luci non corrispondono',{oldLuce, luce});
        }
        const callback = Api.callbackMakeNewLuci;
        Api.callbackMakeNewLuci = null;
        callback(luce);
    }
    static callbackLuciStato = null;
    static toggleForLuciStato = null;
    static fixedCallbackLuciStato = null;
    // /api/luci/stato/
    /**
     * changes the status of a luce on the server
     * @param {luceTemplate} luce the luce to change the status of
     * @returns {*} null if the light's status was changed
     */
    static setLuciStato = (luce,toggle,callback,fixedCallback) => {
        if(Api.fixedCallbackLuciStato == null)
            Api.fixedCallbackLuciStato = fixedCallback;
        if(luce == null)
            throw new Error("luce must be defined");
        if(toggle == null)
            throw new Error("toggle must be defined");
        if(callback == null)
            throw new Error("callback must be defined");

        Api.callbackLuciStato = callback;
        Api.toggleForLuciStato = toggle;
        ApiMqttOut.setLuciStato(luce);
    }
    static sendLuciStatoWeb = response => {
        if(response == null){
            const callback = Api.callbackLuciStato;
            const toggle = Api.toggleForLuciStato;
            Api.callbackLuciStato = null;
            Api.toggleForLuciStato = null;
            callback(toggle);
        } else {
            Api.fixedCallbackLuciStato(response);
        }
    }
    // /api/scenari/
    static callbackGetScenari = null;
    /**
     * gets the scenari of the user from the server
     * @returns {*} all the scenarios of the user
     */
    static getScenari = callback => {
        if(callback == null)
            throw new Error("callback must be defined");
        Api.callbackGetScenari = callback;
        ApiMqttOut.getAllFromScenari();
    };
    static sendScenariWeb = scenari => {
        if( Api.callbackGetScenari == null)
            return;
        const callback = Api.callbackGetScenari;
        Api.callbackGetScenari = null;
        callback(scenari);
    }
    // /api/scenari/attiva/
    static callbackSetScenarioStatus = null;
    static scenarioSetScenarioStatus = null;
    static activatingSetScenarioStatus = null;
    static isActivatingNewScenarioSetScenarioStatus = null;

    /**
     * activates or deactivates a scenario on the server
     * @param {scenarioTemplate} scenario the scenario to activate or deactivate
     * @returns {*} null if the scenario was activated or deactivated
     */
    static setScenarioStatus = (scenario,activating,isActivatingNewScenario,callback) => {
        if(scenario == null)
            throw new Error("scenario must be defined");
        if(activating == null)
            throw new Error("activating must be defined");
        if(isActivatingNewScenario == null)
            throw new Error("isActivatingNewScenario must be defined");
        if(callback == null)
            throw new Error("callback must be defined");
        Api.callbackSetScenarioStatus = callback;
        Api.scenarioSetScenarioStatus = scenario;
        Api.activatingSetScenarioStatus = activating;
        Api.isActivatingNewScenarioSetScenarioStatus = isActivatingNewScenario;
        ApiMqttOut.setScenarioStatus(scenario);
    };
    static sendWebNewScenarioStatus = scenarioNome => {
        if( Api.callbackSetScenarioStatus == null)
            return;
        const callback = Api.callbackSetScenarioStatus;
        const scenario = Api.scenarioSetScenarioStatus;
        const activating = Api.activatingSetScenarioStatus;
        const isActivatingNewScenario = Api.isActivatingNewScenarioSetScenarioStatus;
        Api.callbackSetScenarioStatus = null;
        Api.scenarioSetScenarioStatus = null;
        Api.activatingSetScenarioStatus = null;
        Api.isActivatingNewScenarioSetScenarioStatus = null;
        // FIXME forse dovrei controllare scenarioNome
        if(scenario.nome === scenarioNome) {
            console.log('gli scenari hanno lo stesso nome',{scenario, scenarioNome});
        }
        callback(scenario,activating,isActivatingNewScenario);
    }
    // /api/scenari/registra/
    static recordingRecordScenario = null;
    static endRecordingModalLauncherRecordScenario = null;
    static registraBtnRecordScenario = null;
    static learnINBtnRecordScenario = null;
    static callbackRecordScenario = null;
    /**
     * starts/stop the recording of a scenario
     * @param {Boolean} recording true to start the recording, false to stop it
     * @returns {*} null if the recording was started or stopped
     */
    static recordScenario = (recording,endRecordingModalLauncher,registraBtn,learnINBtn,callback) => {
        if(recording == null)
            throw new Error("recording must be defined");
        if(endRecordingModalLauncher == null)
            throw new Error("endRecordingModalLauncher must be defined");
        if(registraBtn == null)
            throw new Error("registraBtn must be defined");
        if(learnINBtn == null)
            throw new Error("learnINBtn must be defined");
        if(callback == null)
            throw new Error("callback must be defined");
        Api.recordingRecordScenario = recording;//true se voglio registrare
        Api.endRecordingModalLauncherRecordScenario = endRecordingModalLauncher;
        Api.callbackRecordScenario = callback;
        Api.learnINBtnRecordScenario = learnINBtn;
        Api.registraBtnRecordScenario = registraBtn;
        ApiMqttOut.recordScenario(learnINBtn);
    }
    static retriesRecordScenario = 0;
    static sendWebScenarioAutoma = stato => {
        if( Api.callbackRecordScenario == null)
            return;
        const recording = Api.recordingRecordScenario;
        const statoAspettato = recording ? 1 : 0;
        if(stato !== statoAspettato && Api.retriesRecordScenario < 3){
            Api.retriesRecordScenario++;
            ApiMqttOut.recordScenario(Api.learnINBtnRecordScenario);
            return;
        }
        const endRecordingModalLauncher = Api.endRecordingModalLauncherRecordScenario;
        const callback = Api.callbackRecordScenario;
        const registraBtn = Api.registraBtnRecordScenario;
        Api.recordingRecordScenario = null;
        Api.endRecordingModalLauncherRecordScenario = null;
        Api.callbackRecordScenario = null;
        Api.learnINBtnRecordScenario = null;
        Api.registraBtnRecordScenario = null;
        Api.retriesRecordScenario = 0;
        callback(recording,endRecordingModalLauncher,registraBtn);
    }
    // /api/scenari/salva/
    static callbackSaveScenario = null;
    /**
     * tells the server to save the currently recorded scenario
     * @returns {*} the scenario if it was saved
     */
    static saveScenario = (nome,callback) => {
        if(nome == null)
            throw new Error("nome must be defined");
        if(callback == null)
            throw new Error("callback must be defined");
        Api.callbackSaveScenario = callback;
        ApiMqttOut.saveScenario(nome);
    };

    static sendWebSavedScenario = scenario => {
        if( Api.callbackSaveScenario == null)
            return;
        const callback = Api.callbackSaveScenario;
        Api.callbackSaveScenario = null;
        callback(scenario);
    }
    // /api/antifurto/
    /**
     * gets everything about the antifurto (stato, allarme, attenzione (valore progress bar), soglia, sensori)
     * @returns {*} the antifurto's values
     */
    static getAntifurto = async () => {
        
        // const url = Api.baseURL + "antifurto/";
        // const response = await fetch(url);
        // const data = await response.json();
        // if (response.ok)
        //     return data;
        // else
        //     throw data;
    };
    // /api/antifurto/stato/
    /**
     * gets the status of the antifurto
     * @returns {*} the antifurto's status
     */
    /*static getAntifurtoStatus = async () => {
        const url = Api.baseURL + "antifurto/stato/";
        const response = await fetch(url);
        const data = await response.json();
        if (response.ok)
            return data;
        else
            throw data;
    };*/
    static newStatusSetAntifurtoStatus = null;
    static antifurtoINbtnSetAntifurtoStatus = null;
    static payloadSetAntifurtoStatus = null;
    static callbackSetAntifurtoStatus = null;
    /**
     * sets the status of the antifurto
     * @param {Boolean} status the new status of the antifurto
     * @returns {*} null if the status was changed
     */
    static setAntifurtoStatus = (newStatus,antifurtoINbtn,payload,callback) => {
        if(newStatus == null)
            throw new Error("newStatus must be defined");
        if(antifurtoINbtn == null)
            throw new Error("antifurtoINbtn must be defined");
        if(payload == null)
            throw new Error("payload must be defined");
        if(callback == null)
            throw new Error("callback must be defined");
        Api.newStatusSetAntifurtoStatus = newStatus;
        Api.antifurtoINbtnSetAntifurtoStatus = antifurtoINbtn;
        Api.payloadSetAntifurtoStatus = payload;
        Api.callbackSetAntifurtoStatus = callback;
        ApiMqttOut.setAntifurtoStatus(antifurtoINbtn);
    };
    static retriesSetAntifurtoStatus = 0;
    static sendWebAntifurtoAutoma = stato => {
        if( Api.callbackSetAntifurtoStatus == null)
            return;
        const newStatus = Api.newStatusSetAntifurtoStatus;
        const expectedStatus = newStatus ? 2 : 0;
        if(stato !== expectedStatus && Api.retriesSetAntifurtoStatus < 3){
            Api.retriesSetAntifurtoStatus++;
            ApiMqttOut.setAntifurtoStatus(Api.antifurtoINbtnSetAntifurtoStatus);
            return;
        }
        const payload = Api.payloadSetAntifurtoStatus;
        const callback = Api.callbackSetAntifurtoStatus;
        Api.newStatusSetAntifurtoStatus = null;
        Api.antifurtoINbtnSetAntifurtoStatus = null;
        Api.payloadSetAntifurtoStatus = null;
        Api.callbackSetAntifurtoStatus = null;
        Api.retriesSetAntifurtoStatus = 0;
        callback(payload.previousStatus,newStatus,payload.fromScenari,payload.fromServer,payload.fromBellClick);
    }
    // /api/antifurto/allarme/
    /**
     * gets the status of the antifurto's alarm
     * @returns {*} the antifurto's alarm status
     */
    /*static getAntifurtoAllarme = async () => {
        const url = Api.baseURL + "antifurto/allarme/";
        const response = await fetch(url);
        const data = await response.json();
        if (response.ok)
            return data;
        else
            throw data;
    };*/
    /**
     * sets the status of the antifurto's alarm
     * @param {Boolean} allarme the new status of the antifurto's alarm
     * @returns {*} null if the status was changed
     */
    static setAntifurtoAllarme = async allarme => {
        if (allarme == null || typeof allarme.stato !== 'boolean')
            throw new Error("allarme must be a set boolean");
        const url = Api.baseURL + "antifurto/allarme/";
        const response = await fetch(url, {
            method: "PUT",
            headers: {
                "Content-Type": "application/json"
            },
            body: JSON.stringify(allarme)
        });
        if (response.ok)
            return null;
        else
            throw await response.json();
    };
    // /api/antifurto/attenzione/
    /**
     * sets the status for the progress bar of the antifurto's alarm
     * @param {Number} attenzione the new value of the antifurto's attention
     * @returns {*} null if the value was changed 
     */
    static setAntifurtoAttenzione = async attenzione => {
        if (attenzione == null || isNaN(parseInt(attenzione)))
            throw new Error("attenzione must be a set integer");
        const val = parseInt(attenzione);
        if (val < 0 || val > 100)
            throw new Error("attenzione must be between 0 and 100");
        const url = Api.baseURL + "antifurto/attenzione/";
        const response = await fetch(url, {
            method: "PUT",
            headers: {
                "Content-Type": "application/json"
            },
            body: JSON.stringify({attenzione:val})
        });
        if (response.ok)
            return null;
        else
            throw await response.json();
    };
    // /api/antifurto/soglia/
    static sogliaSetAntifurtoSoglia = null;
    static fromServerSetAntifurtoSoglia = null;
    static callbackSetAntifurtoSoglia = null;
    /**
     * sets the value of the antifurto's threshold
     * @param {Number} soglia the user's value of the antifurto's threshold
     * @returns {*} null if the value was changed
     */
    static setAntifurtoSoglia = (soglia,fromServer,callback) => {
        if (soglia == null || isNaN(parseInt(soglia)))
            throw new Error("soglia must be a set integer");
        const val = parseInt(soglia);
        if (val < 0 || val > 100)
            throw new Error("soglia must be between 0 and 100");
            if(fromServer == null)
                throw new Error("fromServer must be defined");
            if(callback == null)
                throw new Error("callback must be defined");
        Api.sogliaSetAntifurtoSoglia = val;
        Api.fromServerSetAntifurtoSoglia = fromServer;
        Api.callbackSetAntifurtoSoglia = callback;
        ApiMqttOut.setAntifurtoSoglia(val);
        /*const url = Api.baseURL + "antifurto/soglia/";
        const response = await fetch(url, {
            method: "PUT",
            headers: {
                "Content-Type": "application/json"
            },
            body: JSON.stringify({soglia:val})
        });
        if (response.ok)
            return null;
        else
            throw await response.json();*/
    };
    static sendWebSoglia = soglia => {
        if( Api.callbackSetAntifurtoSoglia == null)
            return;
        const expectedSoglia = Api.sogliaSetAntifurtoSoglia;
        if(expectedSoglia !== soglia){
            console.log('soglie differenti',{expectedSoglia,soglia});
        }
        const fromServer = Api.fromServerSetAntifurtoSoglia;
        const callback = Api.callbackSetAntifurtoSoglia;
        Api.sogliaSetAntifurtoSoglia = null;
        Api.fromServerSetAntifurtoSoglia = null;
        Api.callbackSetAntifurtoSoglia = null;
        callback(soglia,fromServer);
    }
}

export default Api;