/**
 * Déclenche une opération asynchronise depuis un bouton, devant le mettre à jour !
 * 
 * @param {*} elt 
 * @param {*} url 
 */
async function lcvprestaconnector_ajaxButtonReactionCall(elt, url) {

    // On commence par remplacer le texte du bouton par un loader
    // On cache l'élément (display : none)
    const before = elt.style.display;
    elt.style.display = 'none';

    // On ajoute un loader qu'on affiche juste à côté de l'élément
    const spinner = document.createElement('div');
    spinner.className = 'spinner';
    spinner.style.width = '18px';
    spinner.style.height = '18px';

    const loader = document.createElement('div');
    loader.className = elt.className + ' disabled';
    loader.appendChild(spinner);

    let result = false;

    // Insertion du loader juste après l'élement
    elt.parentNode.insertBefore(loader, elt.nextSibling); 

    try
    {
        const baseUrl = $('body').data('base-url');
        const token = $('body').data('token');

        // Appel ajax pour synchroniser le produit
        const response = await fetch(`${baseUrl}/modules/lcvprestaconnector/${url}&_token=${token}`, {
            method: 'GET',
            JSON: true,
            headers: {
                'Content-Type': 'application/json'
            }
        });        

        if (!response.ok)
            throw new Error('Erreur HTTP : ' + response);

        // Normalement, la réponse devrait contenir un JSON avec une propriété 'success' à vrai
        // Si ce n'est pas le cas, on lève une erreur
        const data = await response.json();
        if (data.success)
        {
            result = true;
        }
        else
        {
            console.error(data);
            // On montre l'erreur avec les fonctions JS prévu par PrestaShop
            showErrorMessage(data.message);            
        }
    }
    catch (e)
    {
        console.error(e);
        showErrorMessage('Erreur : ' + e.message);
    }
    finally
    {
        // On montre l'élément !
        elt.style.display = before;
        // On supprime le loader
        loader.remove();
    }

    return result;
}

/**
 * Déclenche une resynchronisation globale
 */
async function lcvprestaconnector_resyncAll() {
    console.debug('Resynchronisation totale demandée !');

    // Si un bouton avec un id 'page-header-desc-configuration-resync' existe, on le désactive et on change son nom
    const elt = document.getElementById('page-header-desc-configuration-resync');
    
    if (await lcvprestaconnector_ajaxButtonReactionCall(elt, 'resync_all?'))
        elt.innerHTML = 'Resynchro. demandée !';
}

/**
 * Lance une synchronisation
 *  
 */
async function lcvprestaconnector_run(cronGuardToken) {
    console.debug('Lancement de la synchronisation !');

    const elt = document.getElementById('page-header-desc-configuration-run');    

    elt.className = elt.className + ' disabled';
    // On change l'icône du bouton pour un spinner : 
    // pour ça, on cherche dans les fils la balise "i" et on change son contenu
    const i = elt.querySelector('i');
    if (i !== null)
        i.innerHTML = 'sync';

    // Appel ajax vers la tâche cron, sans rien d'autre !
    const baseUrl = $('body').data('base-url');
    const encodedGuardToken = encodeURIComponent(cronGuardToken);
    await fetch(`${baseUrl}/modules/lcvprestaconnector/cron?guard=${encodedGuardToken}`, {
        method: 'GET',
        JSON: true,
        headers: {
            'Content-Type': 'application/json'
        }
    });
}

/**
 * Met à jour l'environnement
 */
async function lcvprestaconnector_pullenv() {
    console.debug('Téléchargement de l\'environnement depuis le backoffice !');

    const elt = document.getElementById('page-header-desc-configuration-pullenv');    

    await lcvprestaconnector_ajaxButtonReactionCall(elt, 'configuration/pullenv?');
}

/**
 * Obtient la progression de la synchronisation en cours ou null si aucune
 * 
 */
async function lcvprestaconnector_getSyncProgress() {

    try
    {
        const baseUrl = $('body').data('base-url');
        const token = $('body').data('token');

        // Appel ajax pour synchroniser le produit
        const response = await fetch(`${baseUrl}/modules/lcvprestaconnector/syncprogress?&_token=${token}`, {
            method: 'GET',
            JSON: true,
            headers: {
                'Content-Type': 'application/json'
            }
        });        

        if (!response.ok)
            throw new Error('Erreur HTTP : ' + response);

        // Normalement, la réponse devrait contenir un JSON avec une propriété 'success' à vrai
        // Si ce n'est pas le cas, on lève une erreur
        const data = await response.json();
        if (data.success)
        {
            return data.progress;
        }
        else
        {
            console.error(data);
            // On montre l'erreur avec les fonctions JS prévu par PrestaShop
            showErrorMessage(data.message);            
        }
    }
    catch (e)
    {
        console.error(e);
        showErrorMessage('Erreur : ' + e.message);
    }

    return null;
}

/**
 * Vérifie la progression de la synchronisation en cours à intervalles réguliers
 */
async function lcvprestaconnector_adminSyncProgressCheck() {

    const elt = document.getElementById('page-header-desc-configuration-run');    
    if (!elt)
        return;

    const result = await lcvprestaconnector_getSyncProgress();
    if (result !== null && result.progress && result.progress.running)
    {
        // On ajoute disabled aux classes CSS s'il n'y est pas déjà 
        if (!elt.className.includes('disabled'))
        {
            elt.className = elt.className + ' disabled';
            // On change l'icône du bouton pour un spinner : 
            // pour ça, on cherche dans les fils la balise "i" et on change son contenu
            const i = elt.querySelector('i');
            if (i !== null)
                i.innerHTML = 'sync';
        }
    }
    else
    {
        // On retire "disabled" des classes CSS
        if (elt.className.includes('disabled'))
        {
            elt.className = elt.className.replace('disabled', '');
            // On change l'icône du bouton pour une icône play
            const i = elt.querySelector('i');
            if (i !== null)
                i.innerHTML = 'play_circle';
        }
    }
}

/**
 * Affiche la progression de la synchronisation en cours
 */
async function lcvprestaconnector_dashboardSyncProgressShow(progress)
{
    const elt = document.getElementById('lcvprestaconnector_dashboard_progress');    
    if (!elt)
        return;

    if (progress)
    {
        if (progress.running)
        {            
            let html = '<p><strong>Synchronisation en cours</strong>, démarrée depuis ';
            
            // On marque la durée de la synchronisation, du style : démarrée depuis 24minutes et 30 secondes...
            const startTimestamp = progress.startTime * 1000;
            const nowTimestamp = Date.now();
            const diffDate = new Date(nowTimestamp - startTimestamp);

            if (diffDate.getTime() > 60000)
            {
                if (diffDate.getTime() > 3600000)
                    html += `${diffDate.getUTCHours()}h et ${diffDate.getUTCMinutes()}mins`;
                else
                    html += `${diffDate.getUTCMinutes()}mins`;
            }
            else
                html += 'quelques instants';

            html += '</p>';

            html += '<ul>';
            // foreach pour parcourir les clés de l'objet progress.steps
            for (const key in progress.steps)
            {
                const step = progress.steps[key];

                if ( (step.e ?? false) && (step.errMsg ?? false) )
                    html += '<li style="list-style-type: \'❌\'; text-decoration: line-through; color: crimson;"> ' + step.errMsg + ' </li>';
                else if (step.e ?? false)
                    html += '<li style="list-style-type: \'✅\'; text-decoration: line-through; color: darkgray;"> ' + step.m + ' </li>';
                else if (step.d > 0)
                    html += '<li class="blinking-text" style="list-style-type: \'🔄\';">' + step.m + '(' + step.d + ')' + '</li>';
                else
                    html += '<li class="blinking-text" style="list-style-type: \'🔄\';">' + step.m + '</li>';
            }

            html += '</ul>';

            //const perc = progress.stepNb > 0 ? Math.round(progress.stepDone * 100 / progress.stepNb) : 0;

            
            /*html += `<div class="progress"><div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" 
                        style="width: ${perc}%"></div></div>`;*/                        

            elt.innerHTML = html;
        }
        else
        {
            if (progress.endTime)
            {            
                const endTimestamp = progress.endTime * 1000;
                const nowTimestamp = Date.now();
                const ellapsedTime = (nowTimestamp - endTimestamp) / 1000;

                let diffStr = '';            
                if (ellapsedTime < 60)
                    diffStr = 'moins d\'une minute';
                else if (ellapsedTime < 3600)
                    diffStr = Math.floor(ellapsedTime / 60) + ' minutes';
                else if (ellapsedTime < 86400 * 3)
                    diffStr = Math.floor(ellapsedTime / 3600) + ' heures';
                else
                    diffStr = Math.floor(ellapsedTime / 86400) + ' jours';

                elt.innerHTML = '<p>Dernière synchronisation il y a ' + diffStr + '.</p>';

                // On scanne les messages à la recherche d'erreurs
                const errors = [];
                for (const [stepKey, stepData] of Object.entries(progress.steps)) {
                    if (stepData.errMsg) {
                        errors.push({
                            step: stepKey,
                            message: stepData.errMsg
                        });
                    }
                }

                if (errors.length > 0) {
                    // On ajoute les erreurs en orange en bas du message, max 120 caractères par message d'erreur, avec une icône d'erreur
                    let errorHtml = '<div class="sync-error"><p><strong>Erreurs rencontrées lors de la dernière synchronisation :</strong></p><ul>';
                    errors.forEach(error => {
                        let message = error.message;
                        if (message.length > 120) {
                            message = message.substring(0, 120) + '…';
                        }
                        errorHtml += `<li><strong>${error.step}:</strong> ${message}</li>`;
                    });
                    errorHtml += '</ul></div>';

                    elt.innerHTML = elt.innerHTML + errorHtml;
                }
            } 
            else
            {
                elt.innerHTML = '<p>Pas encore synchronisé.</p>';
            }

            if (progress.lastErrorMsg)
            {
                // Tronquer le message d'erreur à 100 caractères
                if (progress.lastErrorMsg.length > 120)
                    progress.lastErrorMsg = progress.lastErrorMsg.substring(0, 120) + '…';
                elt.innerHTML = '<div class="sync-error"><p>' + progress.lastErrorMsg + '</p></div>' + elt.innerHTML;
            }

            // La synchro était marquée "en cours" mais le process est mort avant la fin :
            // arrêt anormal (erreur fatale, mémoire saturée…). On l'affiche en tête.
            if (progress.aborted)
            {
                elt.innerHTML = '<div class="sync-error"><p><strong>⚠️ La dernière synchronisation '
                    + 's\'est interrompue anormalement</strong> (le traitement s\'est arrêté avant la fin). '
                    + 'La cause est probablement dans les journaux PHP (erreur fatale, mémoire saturée…).</p>'
                    + '</div>' + elt.innerHTML;
            }
        }
    }
    else
    {
        elt.innerHTML = '<p>Impossible d\'obtenir l\'état de la synchronisation</p>';
    }
}

/**
 * Déclenche la synchronisation d'un produit spécifique
 * @param {*} e évènement déclencheur
 * @param {*} id_product 
 * 
 */
async function lcvprestaconnector_syncProduct(e, id_product) {    
    
    console.debug('Synchronisation du produit ' + id_product);
    const elt = e.currentTarget;    

    if (await lcvprestaconnector_ajaxButtonReactionCall(elt, `sync_product?id_product=${id_product}`))
        document.location.reload();
}

/**
 * Déclenche la synchronisation d'une commande spécifique
 * @param {*} elt élement déclencheur
 * @param {*} id_product 
 * 
 */
async function lcvprestaconnector_exportOrder(elt, order_reference) {    
    
    console.debug('Exportation de la commande ' + order_reference);

    if (await lcvprestaconnector_ajaxButtonReactionCall(elt, `export_order?order_reference=${order_reference}`))
        document.location.reload();
}

/**
 * Déclenche la synchronisation d'un produit spécifique
 * @param {*} e évènement déclencheur
 * @param {*} id_product 
 * 
 */
async function lcvprestaconnector_toggleLockProduct(e, id_product) {    
    
    console.debug('Lock/Unlock produit ' + id_product);
    const elt = e.currentTarget;    
    const action = elt.innerHTML.includes('lock_open') ? 'lock' : 'unlock';

    if (await lcvprestaconnector_ajaxButtonReactionCall(elt, `lock_product?id_product=${id_product}&action=${action}`))
        document.location.reload();
}
