"use strict";
import Luci from './luci.js';
import Antifurto from './antifurto.js';
import { scenariToggleListener } from "./toggles.js";
import { showAlert, makeElementBounce } from "./alerts.js";

// JSON templeate for scenario
export interface scenarioTemplate {
    "nome": string,
    "data": string,
    "id": string,
};

class Scenari {
    /**
     * the div where everything related to the Scenari is stored
     */
    static scenariContainer = document.getElementById('scenariContainer')!;
    /**
     * this is the select element where to add all the scenarios
     */
    static addNameHere = document.getElementById('p')! as HTMLSelectElement;
    /**
     * contains the toggle that is currently active
     */
    static scenarioAttivoToggle: HTMLElement | null = null;
    /**
     * counts how many scenarios have been added
     */
    static index = 0;
    /**
     * the array where all of the user's scenari are stored
     */
    static scenariBucket: scenarioTemplate[] = [];

    constructor() {
        Scenari.init();
        Scenari.antifurtoModalLauncherListener();
        Scenari.anyModalListener();
    }
    /**
     * sets up the listener for the button in the top of the page
     * i'm also leaving here what I haven't yet implemented
     */
    static init(): void {
        Scenari.fillTable();

        const scenariBtn = document.getElementById('mainButtonContainer')!.children[1];
        scenariBtn.addEventListener('click', () => {
            Scenari.toggleContainer(true);
            Luci.toggleContainer(false);
            Antifurto.toggleContainer(false);
        }, false);

        const registerBtn = document.getElementById('scenari-registra')!;
        registerBtn.addEventListener('click', event => {
            event.preventDefault();
            // TODO choose how to register the scenario
        }, false);
    }
    /**
     * used for the antitheft button (ON/OFF): before opening the connected modal, change its text then open it
     * @see Scenari.antifurtoModalSubmitListener
     */
    static antifurtoModalLauncherListener(): void {
        const antifurtoBtn = document.getElementById('scenari-stato-antifurto')!;
        const okBtn = document.getElementById('attiva-antifurto-btn')!;
        const modalBody = document.querySelector('#antifurto-modal .modal-body')!;
        const modalLauncher = document.getElementById('lancia-antifurto-modal')!;
        const registerBtn = document.getElementById('scenari-registra')!;

        antifurtoBtn.addEventListener('click', () => {
            if (registerBtn.innerText !== "Registra") {//sto registrando
                showAlert("Attenzione", "Stai registrando uno scenario, termina la registrazione per attivare l'antifurto.", false);
                makeElementBounce(registerBtn);
                return;
            }
            if (Scenari.scenariBucket.length === 0) {
                showAlert('Nessun scenario disponibile', 'Registrare uno o più scenari per poter attivarne uno', false);
                // make the registerBtn bounce for 3 seconds
                const registerBtn = document.getElementById('scenari-registra');
                makeElementBounce(registerBtn);
                return;
            }
            const children = modalBody.children as HTMLCollectionOf<HTMLElement>;
            // 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 {
                // the antitheft is off
                children[0].innerText = "Stai per abilitare l'antifurto.";
                okBtn.innerText = 'Attiva';
            }
            // launch the modal
            modalLauncher.click();
            // related: Scenari.antifurtoModalSubmitListener();
        }, false);

        // TODO server get antifurto status and set it correctly
        // toggleAntifurto(response);
    }
    /**
     * sets up various listeners for the modals
     * @see Scenari.attivaScenarioModal
     * @see Scenari.registraModal
     * @see Scenari.antifurtoModalSubmitListener
     */
    static anyModalListener(): void {
        Scenari.anteprimaModal();
        Scenari.attivaScenarioModal();
        Scenari.registraModal();
        Scenari.antifurtoModalSubmitListener();
    }
    /**
     * listens to the submit button in the modal for the antitheft and activates/deactivates the antitheft
     * this modal is shown when the user clicks on the antitheft button
     * @see Scenari.antifurtoModalLauncherListener
     */
    static antifurtoModalSubmitListener(): void {
        const antifurtoOkBtn = document.getElementById('attiva-antifurto-btn')!;
        const closeBtn = document.querySelector('#antifurto-modal .btn.btn-danger')! as HTMLButtonElement;
        const antifurtoBtn = document.getElementById('scenari-stato-antifurto')!;
        antifurtoOkBtn.addEventListener('click', () => {
            // close modal
            closeBtn.click();
            // switch the antitheft status button
            const isActivatingAntitheft = antifurtoBtn.innerText === 'OFF';
            // Scenari.toggleAntifurto(isActivatingAntitheft);
            if (isActivatingAntitheft)
                Scenari.activateRandomScenario();
            else
                Scenari.deactivateActiveScenario();//cannot use toggleScenario because I don't have the scenarioID
            // Antifurto.activate(isActivatingAntitheft) already taken care of
        }, false);
    }
    /**
     * listens for the submit of the anteprima modal
     */
    static anteprimaModal(): void {
        const anterprimaModal = document.getElementById('anteprima-modal')!;
        const okBtn = anterprimaModal.querySelector('#anteprima-scenari-btn')! as HTMLButtonElement;
        const modalBody = anterprimaModal.querySelector('.modal-body')!;
        const closeBtn = anterprimaModal.querySelector('.btn.btn-danger')! as HTMLButtonElement;
        okBtn.addEventListener('click', () => {//activate the scenario
            // close the modal
            closeBtn.click();
            // get the scenario from the modal body
            const scenarioID = (modalBody.querySelector('.invisible')! as HTMLElement).innerText;
            // find the scenario's row on the page
            // const scenarioRow = scenarioTable.querySelector(`#${scenarioName}`);
            // const toggle = scenarioTable.querySelector(`#${scenarioName} .toggle-button`);
            Scenari.toggleScenario(scenarioID, okBtn.innerText === 'Attiva');
        }, false);
    }
    /**
     * listenes for the submit button in the modal for activating/deactivating a scenario when chosen from the toggles
     * @see scenariToggleListener
     */
    static attivaScenarioModal(): void {
        const modalBtn = document.getElementById('attiva-scenari-btn')!;
        const closeBtn = document.querySelector('#attiva-scenari-modal .btn.btn-danger')! as HTMLButtonElement;

        modalBtn.addEventListener('click', () => {
            // close the modal by clicking on the close button
            closeBtn.click();
            // I have to get to the toggle and activate it from the value of the select
            const scenarioID = Scenari.addNameHere.value;
            const toggle = document.querySelector(`#${scenarioID} .toggle-button`);
            // has the user chosen to activate the scenario?
            // const isActivatingNewScenario = ;
            // Scenari.toggleToggle(toggle,isActivatingNewScenario);
            // Scenari.toggleAntifurto(isActivatingNewScenario);
            Scenari.toggleScenario(scenarioID, toggle !== Scenari.scenarioAttivoToggle);
        }, false);
    }
    /**
     * this is for the button "registra"/"termina" and the related modals
     * @see Scenari.registraBtnListener
     * @see Scenari.submitRecordModalListener
     * @see Scenari.endRecordingListener
     */
    static registraModal(): void {
        const scenariModal = document.getElementById('scenari-modal')!;

        const registraBtn = document.getElementById('scenari-registra') as HTMLButtonElement;
        const okBtn = scenariModal.querySelector('.btn.btn-info') as HTMLButtonElement;
        const modalBody = scenariModal.querySelector('.modal-body') as HTMLElement;
        const htmlForModalBody = `<p>Stai per attivare la registrazione dei comandi.</p>
        <p>Dal momento in cui premerai sul bottone azzurro, inizierai a registrare tutte le interazioni con le tue luci.</p>
        <p>Inoltre disabiliterai eventuali scenari attivi.</p>
        <p>Una volta che sarai soddisfatto del risultato, torna su questa pagina per terminare la registrazione.</p>
        <p>Inizare la registrazione?</p>`
        const modalLauncher = document.getElementById('registra-modal-launcer') as HTMLButtonElement;

        // const okBtn = scenariModal.querySelector('.btn.btn-info');
        // const registraBtn = document.getElementById('scenari-registra');
        const closeScenariModalBtn = scenariModal.querySelector('.btn.btn-danger') as HTMLButtonElement;
        const endRecordingModalLauncher = document.getElementById('termina-registrazione-launcher') as HTMLButtonElement;

        const endRecordingForm = document.getElementById('termina-registrazione-form') as HTMLFormElement;
        // const modalBody = scenariModal.querySelector('.modal-body');
        // htmlForModalBody = ...
        const closeRecordingBtn = document.getElementById('termina-registrazione-modal')!.querySelector('.btn.btn-danger') as HTMLButtonElement;
        const campoNome = document.getElementById('nome-nuovo-scenario') as HTMLInputElement;


        Scenari.registraBtnListener(registraBtn, okBtn, modalBody, htmlForModalBody, modalLauncher);
        Scenari.submitRecordModalListener(okBtn, registraBtn, closeScenariModalBtn, endRecordingModalLauncher);
        Scenari.endRecordingListener(endRecordingForm, modalBody, htmlForModalBody, closeRecordingBtn, campoNome);
    }
    /**
     * listens for the actual "registra"/"termina" button on the page and edits the related modal accordingly
     * @param {HTMLButtonElement} registraBtn the button on the page
     * @param {HTMLButtonElement} okBtn the submit button in the modal
     * @param {HTMLElement} modalBody the body of the modal which is to be changed
     * @param {string} htmlForModalBody a string containing the html to be inserted in the modal body
     * @param {HTMLButtonElement} modalLauncher the button which launches the modal
     * @see Scenari.registraModal
     */
    static registraBtnListener(registraBtn: HTMLButtonElement, okBtn: HTMLButtonElement, modalBody: HTMLElement, htmlForModalBody: string, modalLauncher: HTMLButtonElement): void {
        registraBtn.addEventListener('click', () => {
            const isAboutToRecord = registraBtn.innerText === 'Registra';
            // change text of okBtn
            okBtn.innerText = isAboutToRecord ? 'Registra' : 'Termina';
            // change inner text of the modal

            if (isAboutToRecord) {
                modalBody.innerHTML = htmlForModalBody;
            } else {
                modalBody.innerHTML = `
                <p>Stai per terminare la registrazione dei comandi.</p>
                <p>Terminare la registrazione?</p>`;
            }
            // launch the modal
            modalLauncher.click();
            // related: Scenari.submitRecordModalListener
        }, false);
    }
    /**
     * listens for the submit of the modal which is launched when the user clicks on the "registra"/"termina" button
     * @param {HTMLButtonElement} okBtn the submit button in the modal
     * @param {HTMLButtonElement} registraBtn the button on the page (to understand if the user is about to record or not)
     * @param {HTMLButtonElement} closeScenariModalBtn the button used to close the modal
     * @param {HTMLButtonElement} endRecordingModalLauncher the button which launches the next modal (used if the user has finished recording)
     * @see Scenari.registraModal
     */
    static submitRecordModalListener(okBtn: HTMLButtonElement, registraBtn: HTMLButtonElement, closeScenariModalBtn: HTMLButtonElement, endRecordingModalLauncher: HTMLButtonElement): void {
        okBtn.addEventListener('click', () => {
            const isAboutToRecord = registraBtn.innerText === 'Registra';
            // close modal
            closeScenariModalBtn.click();
            // get the current time
            // const timeBegin = new Date();

            // if the user ended the recording, show another modal to ask for the name of the scenario
            if (isAboutToRecord) {
                registraBtn.innerText = 'Termina';
                // TODO server send a note to start recording
                Scenari.deactivateActiveScenario();
            } else {
                registraBtn.innerText = 'Registra';
                // TODO server send a note to stop recording
                endRecordingModalLauncher.click();
                // related: Scenari.endRecordingListener
            }
        }, false);
    }
    /**
     * listens for the submit of the modal which is launched when the user is done recording a scenario
     * @param {HTMLFormElement} endRecordingForm the form used to submit the name of the scenario
     * @param {HTMLElement} modalBody the body of the modal which is to be changed
     * @param {string} htmlForModalBody a string containing the html to be inserted in the modal body
     * @param {HTMLButtonElement} closeRecordingBtn the button used to close the modal
     * @param {HTMLInputElement} campoNome the input field used to insert the name of the scenario by the user
     * @see Scenari.registraModal
     * @see Scenari.mostraNuovoScenario
     */
    static endRecordingListener(endRecordingForm: HTMLFormElement, modalBody: HTMLElement, htmlForModalBody: string, closeRecordingBtn: HTMLButtonElement, campoNome: HTMLInputElement): void {
        endRecordingForm.addEventListener('submit', (event: { preventDefault: () => void; }) => {
            event.preventDefault();
            // reset the other modal and button
            modalBody.innerHTML = htmlForModalBody;
            // close the modal
            closeRecordingBtn.click();

            const name = campoNome.value;
            const scenario = Scenari.createScenarioFromName(name)
            Scenari.mostraNuovoScenario(scenario);

            // clear the field for the next use
            campoNome.value = '';
            // TODO server send a note to save the scenario
        }, false);
    }
    /**
     * takes care of launching a modal to preview the actions of the chosen scenario; it also listens for the submit of the launched modal
     * @param {HTMLButtonElement} anteprimaBtn the button used to launch the modal
     * @param {scenarioTemplate} scenario the JSON scenario to be previewed
     * @see Scenari.correctlySetToggle
     */
    static anteprimaListener(anteprimaBtn: HTMLButtonElement, scenario: scenarioTemplate): void {
        const scenarioID = scenario.id;
        const anterprimaModal = document.getElementById('anteprima-modal')!;
        const modalBody = anterprimaModal.querySelector('.modal-body')!;
        const modalLauncher = document.getElementById('anteprima-modal-launcher')!;
        const okBtn = anterprimaModal.querySelector('#anteprima-scenari-btn')! as HTMLButtonElement;
        const scenarioTable = document.getElementById('table-row-scenari')!;
        const registerBtn = document.getElementById('scenari-registra')!;

        anteprimaBtn.addEventListener('click', () => {
            if (registerBtn.innerText !== "Registra") {//sto registrando
                showAlert("Attenzione", "Stai registrando uno scenario, termina la registrazione per mostrare l'anteprima.", false);
                makeElementBounce(registerBtn);
                return;
            }
            // TODO server get the scenario's data 
            // show the scenario in the modal (choose how to display it)
            modalBody.innerHTML = `
            <p>${scenario.nome}</p>
            <p>${scenario.data}</p>
            <span class='invisible'>${scenarioID}</span>`;//FIXME remove this test (be sure to keep the last span as is)
            // if the scenario is already active, change the okBtn text
            // to find if it's active, find the relative toggle
            // and check if it's active
            // const scenarioRow = scenarioTable.querySelector(`#${name}`);
            const toggle = scenarioTable.querySelector(`#${scenarioID} .toggle-button`)!;
            okBtn.innerText = toggle.classList.contains('active') ? 'Disattiva' : 'Attiva';
            // launch the modal
            modalLauncher.click();
        }, false);
    }
    // utilility functions
    /**
     * displays the given scenario on the screen (below every other one) and hooks up the listeners; then it increments the index
     * @param {scenarioTemplate} scenario the JSON scenario to be displayed
     * @see Scenari.createScenarioRow
     * @see Scenari.anteprimaListener
     * @see scenariToggleListener
     */
    static mostraNuovoScenario(scenario: scenarioTemplate): void {
        const row = Scenari.createScenarioRow(scenario);
        const scenarioID: string = scenario.id;
        const tableBody = document.getElementById('table-row-scenari')!;
        tableBody.appendChild(row);

        const anteprimaBtn = row.querySelector('.badge.rounded-pill') as HTMLButtonElement;
        Scenari.anteprimaListener(anteprimaBtn, scenario);

        // add the name of the scenario as option in the select of the modal
        const option = document.createElement('option');
        option.value = scenarioID;
        option.innerText = scenario.nome;
        Scenari.addNameHere.appendChild(option);

        const toggle = row.querySelector('.toggle-button') as HTMLElement;
        scenariToggleListener(toggle, scenarioID);

        // Scenari.index++;
    }
    /**
     * creates a table entry for the given scenario and returns it
     * @param {scenarioTemplate} scenario the JSON scenario to be displayed
     * @returns {HTMLTableRowElement} the row containing the given scenario
     */
    static createScenarioRow(scenario: scenarioTemplate): HTMLTableRowElement {
        const row = document.createElement('tr');
        row.id = scenario.id;
        row.innerHTML = `
        <th scope="row">${scenario.nome.trim()}</th>
        <td>
            <span>${scenario.data}</span>
        </td>
        <td>
            <h5>
                <span class="badge rounded-pill bg-secondary">anteprima</span>
            </h5>
        </td>
        <td>
            <div class="switch-container no-box-sizing">
                <div id="toggle-${scenario.id}" class="toggle-button no-box-sizing">
                    <div class="inner-circle no-box-sizing"></div>
                </div>
            </div>
            <span id="launch-modal-${scenario.id}" data-bs-toggle="modal" data-bs-target="#attiva-scenari-modal"></span>
        </td>`;
        // the span is used by the toggle to launch the modal
        return row;
    }
    /**
     * changes the antifurto button to the given state
     * @param {Boolean} activating true if the antitheft is being activated, false otherwise
     * @param {Boolean} fromAntifurto usually false or undefined; true only if the function is called from the scenari
     */
    static correctlySetAntifurto(activating: Boolean, fromAntifurto: Boolean = false): void {
        if (fromAntifurto !== true)
            Antifurto.activate(activating, true);

        const antifurtoBtn = document.getElementById('scenari-stato-antifurto')!;
        if (activating) {
            if (antifurtoBtn.innerText === 'ON')
                return;
            antifurtoBtn.innerText = 'ON';
            antifurtoBtn.classList.remove('btn-danger');
            antifurtoBtn.classList.add('btn-success');
        } else {
            if (antifurtoBtn.innerText === 'OFF')
                return;
            antifurtoBtn.innerText = 'OFF';
            antifurtoBtn.classList.remove('btn-success');
            antifurtoBtn.classList.add('btn-danger');
        }
    }
    /**
     * turns off the active scenario if there is one; useful if you don't have the scenarioID
     */
    static deactivateActiveScenario(): void {
        if (Scenari.scenarioAttivoToggle == null)
            return;
        // Scenari.scenarioAttivoToggle.classList.remove('active');
        // Scenari.scenarioAttivoToggle = null;
        // // TODO server deactivate the scenario
        const toggleID = Scenari.scenarioAttivoToggle.id;
        const scenarioID = toggleID.substring(toggleID.indexOf('-') + 1);
        Scenari.toggleScenario(scenarioID, false);
    }
    /**
     * activates/deactivates the scenario with the given name
     * @param {string} scenarioID the ID of the scenario to be activated/deactivated
     * @param {Boolean} activating true if the scenario should be activated, false otherwise
     */
    static toggleScenario(scenarioID: string, activating: Boolean) {
        // find the scenario's row on the page
        const scenarioRow = document.getElementById(`${scenarioID}`)!;
        const toggle = scenarioRow.querySelector('.toggle-button') as HTMLElement;
        Scenari.correctlySetToggle(toggle);
        Scenari.correctlySetAntifurto(activating);
        // if (activating) {
        //     // TODO server activate the scenario
        // } else {
        //     // TODO server deactivate the scenario
        // }
    }
    /**
     * takes care of activating or deactivating the scenario's toggle based on the given boolean
     * @param {HTMLElement} toggle the toggle to be activated or deactivated
     * @see Scenari.correctlySetAntifurto
     */
    static correctlySetToggle(toggle: HTMLElement): void {
        const isActivatingNewScenario = toggle !== Scenari.scenarioAttivoToggle;
        Scenari.scenarioAttivoToggle?.classList.remove('active');
        if (isActivatingNewScenario) {
            toggle.classList.add('active');
            Scenari.scenarioAttivoToggle = toggle;
        } else {
            toggle.classList.remove('active');
            Scenari.scenarioAttivoToggle = null;
        }
    }
    /**
     * activates a random scenario from the ones available
     */
    static activateRandomScenario(): void {
        if (Scenari.scenariBucket.length === 0) {
            showAlert('Nessun scenario disponibile', 'Registrare uno o più scenari per poter attivarne uno', false);
            // make the registerBtn bounce for 3 seconds
            const registerBtn = document.getElementById('scenari-registra');
            makeElementBounce(registerBtn);
            return;
        }
        const randomIndex = Math.floor(Math.random() * Scenari.index);
        const scenarioID = `scenario-${randomIndex}`;
        // const table = document.getElementById('table-row-scenari');
        // // enable a random scenario
        // const randomScenario = table.children[Math.floor(Math.random() * table.children.length)];
        // const scenarioID = randomScenario.id;
        Scenari.toggleScenario(scenarioID, true);
    }
    /**
     * creates the scenario and updates index
     * @param {string} scenarioName the string of the scenario to create
     * @returns {scenarioTemplate} the JSON scenario
     */
    static createScenarioFromName(scenarioName: string): scenarioTemplate {
        const scenario: scenarioTemplate = {
            nome: scenarioName,
            data: new Date().toLocaleString(),
            id: `scenario-${Scenari.index}`,
        };
        Scenari.index++;
        Scenari.scenariBucket.push(scenario);
        return scenario;
    }
    /**
     * fills the table with the scenarios available for the user in the server
     * @see Scenari.mostraNuovoScenario
     */
    static fillTable(): void {
        // TODO server get all scenarios
        const scenari = [];

        for (const scenario of scenari) {
            Scenari.mostraNuovoScenario(scenario)
            // TODO server if scenario is active, change the toggle to active
            // also set Scenari.scenarioAttivoToggle to its toggle
        }
    }
    /**
     * toggle the visibility of the scenari container
     * @param {Boolean} visible true if the container should be shown, false otherwise
     */
    static toggleContainer(visible: Boolean): void {
        if (visible) {
            Scenari.scenariContainer.classList.remove('invisible');
            if (Scenari.scenariBucket.length === 0) {
                // make the register button bounce
                const registerBtn = document.getElementById('scenari-registra');
                makeElementBounce(registerBtn);
            }
        } else {
            Scenari.scenariContainer.classList.add('invisible');
        }
    }
}

export default Scenari;