import { toast } from 'react-toastify';
import AGGridConfigurationAdministres from '../components/Commun/listes/configuration/AGGridConfigurationAdministres';
import AGGridConfigurationPostes from '../components/Commun/listes/configuration/AGGridConfigurationPostes';
import { DECISIONS } from '../constantes/constantes';
import i18n from '../i18n/i18n';
import AppConfigStore from '../stores/AppConfigStore';
import { getDecisionLabel } from './i18n-helper';

/**
 * Classe effectuant des actions métier sur le back-end.
 * - opérations sur les postes et administrés des sous-viviers
 * - création, mise à jour ou suppression de décisions entre un administré et un poste
 * - lancement des calculs
 * - ...
 * @class
 */
export default class ActionsMetierHelper {

    /**
     * @constructor
     * @param {?AppConfigStore} appConfig
     */
    constructor(appConfig) {
        /** @type {?AppConfigStore} appConfig */
        this.appConfig = appConfig;
    }

    /**
     * Affiche la fiche détaillée d'un administré dans une pop-in.
     *
     * @async
     * @param {import('../jsdoc/api').IdAdministreApi} idAdministre - ID de l'administré
     */
    async afficherFicheDetailleeAdministre(idAdministre) {
        this.appConfig.setAdministreFicheDetaillee(idAdministre);
    }

    /**
     * Exclut un administré du sous-vivier actuel.
     *
     * @async
     * @param {Object} administre - Data de l'administré
     */
    async exclureAdministreDuSousVivier(administre) {
        //TODO afficher le message de confirmation via une modale avec les boutons "OK" et "Annuler" (donc à gérer en asynchrone !)
        let msgConfirmation =
            "Confirmez-vous l'exclusion de l'administré\n      " +
            administre.identite_grade_nom_prenom +
            '\ndu sous-vivier\n      ' +
            administre.perimetre_sousVivier_libelle +
            '\n?';

        if (!window.confirm(msgConfirmation)) {
            toast.info('Opération annulée.');
            return;
        }
        try {
            await this.appConfig.managers.administres.update(administre.id, { sous_vivier_id: null });
            toast.success(
                "L'administré « " +
                    administre.identite_grade_nom_prenom +
                    ' » a bien été exclu du sous-vivier « ' +
                    administre.perimetre_sousVivier_libelle +
                    ' ». Pensez à en informer le gestionnaire qui devra dorénavant le prendre en charge.'
            );
        } catch (reason) {
            console.error(reason);
            toast.error(
                "Erreur d'exclusion de l'administré « " +
                    administre.identite_grade_nom_prenom +
                    ' »  du sous-vivier « ' +
                    administre.perimetre_sousVivier_libelle +
                    ' »',
                { autoClose: false }
            );
        }
    }

    /**
     * Ajoute un poste à un autre sous-vivier
     *
     * @async
     * @param {Object} poste - Data du poste
     * @param {import('../jsdoc/api').IdSousVivierApi} sv_id - ID du sous-vivier
     */
    async ajoutPosteAuSousVivier(poste, sv_id) {
        // TODO afficher le message de confirmation via une modale avec les boutons "OK" et "Annuler" (donc à gérer en asynchrone !)
        let msgConfirmation =
            "Confirmez-vous l'ajout du poste\n      " +
            poste +
            '\nau sous-vivier\n      ' +
            sv_id +
            '\n?';

        if (!window.confirm(msgConfirmation)) {
            toast.info('Opération annulée.');
            return;
        } else {
            try {
                await this.appConfig.managers.postes.update(poste, { sous_vivier_id: sv_id });
                toast.success(
                    "Le poste « " +
                    poste +
                        ' » a bien été ajouter au sous-vivier « ' +
                        sv_id +
                        ' ». Pensez à en informer le gestionnaire qui devra aussi le prendre en charge.'
                );
            } catch (reason) {
                console.error(reason);
                toast.error(
                    "Erreur d'ajout du poste « " +
                    poste +
                        ' »  au sous-vivier « ' +
                        sv_id +
                        ' »',
                    { autoClose: false }
                );
            }
        }
    }

    /**
     * Ajoute ou met à jour la décision (plus précisément son statut) liant un administré à un poste.
     *
     * @async
     * @param {import('../jsdoc/api').IdAdministreApi} administreId - Id de l'administré
     * @param {import('../jsdoc/api').IdPosteApi} posteId - Id du poste
     * @param {string} nouvelleDecision - Nouvelle décision
     * @param {string} decisionActuelle - Décision actuelle
     * @param {function} [onCancelOrError] - Callback à appeler en cas d'erreur ou d'annulation
     * @param {boolean} [sansConfirmation=false] - Indique s'il faut réaliser l'action sans demander confirmation à l'utilisateur
     * @returns {?Promise<boolean>} true si la requête distante a réussi
     */
    async creeOuMAJDecisionAdministreAvecPoste(
        administreId,
        posteId,
        nouvelleDecision,
        decisionActuelle,
        onCancelOrError = () => {},
        sansConfirmation = false
    ) {
        const logPrefix = 'creeOuMAJDecisionAdministreAvecPoste';
        console.log(logPrefix, { administreId, posteId, nouvelleDecision, decisionActuelle, sansConfirmation });

        if (administreId === null || administreId === undefined || administreId === '' || posteId === null || posteId === undefined || posteId === '') {
            throw "l'administré et le poste sont obligatoires pour mettre à jour une décision";
        }

        const annee = this.appConfig.PAMSelectionne;

        // const params_administre = {};
        // annee && (params_administre.pam__in = annee);

        // const params_poste = {};
        // annee && (params_poste.pam__in = annee);
        // annee && (params_poste.pam_annee = annee);
        // --- Chargement des détails sur l'administré/le poste pour vérifier s'ils ne sont pas déjà liés à un autre poste/administré
        const managers = this.appConfig.managers;
        const [responseAdministre, responsePoste] = await Promise.all([
            managers.administres.fetch([administreId,annee].join('')),
            managers.postes.fetch([posteId,annee].join(''))
        ]);
        //console.log('PROMESSE TENUE responseAdministre', responseAdministre?.data);
        //console.log('PROMESSE TENUE responsePoste', responsePoste?.data);

        const refs = this.appConfig.donneesReference;
        const agGridConfigurationAdministres = new AGGridConfigurationAdministres(refs);
        const administre = agGridConfigurationAdministres.adapteAdministre(responseAdministre?.data);

        const agGridConfigurationPostes = new AGGridConfigurationPostes(refs);
        const poste = agGridConfigurationPostes.adaptePoste(responsePoste?.data);

        console.log(`${logPrefix} administre`, responseAdministre?.data);
        console.log(`${logPrefix} poste`, responsePoste?.data);

        //TODO afficher le message de confirmation dans une pop-in
        //Si la nouvelle décision est une suppression de décision, on fixe nouvelleDécision sur DECISIONS.AUCUNE
        nouvelleDecision = !nouvelleDecision || nouvelleDecision.length === 0 ? DECISIONS.AUCUNE : nouvelleDecision;
        let msgConfirmation = 'Confirmez-vous ';

        if (nouvelleDecision === DECISIONS.AUCUNE) {
            if (decisionActuelle === DECISIONS.AUCUNE) {
                console.warn(`${logPrefix} - décision actuelle vide : ${decisionActuelle}`);
                onCancelOrError();
                return false;
            }
            if (!refs.decisionsById?.has(decisionActuelle)) {
                console.error(`${logPrefix} - décision actuelle inconnue : ${decisionActuelle}`);
                onCancelOrError();
                return false;
            }
            msgConfirmation += "l'annulation " + (i => i?.confirmationAnnulation ?? `du statut "${getDecisionLabel(decisionActuelle, refs)}"`)(i18n.decision?.[decisionActuelle]);
        }
        else if (!refs.decisionsById?.has(nouvelleDecision)) {
            console.error(`${logPrefix} - décision inconnue : ${nouvelleDecision}`);
            onCancelOrError();
            return false;
        }
        else {
            msgConfirmation += (i => i?.confirmation ?? `le statut "${getDecisionLabel(nouvelleDecision, refs)}"`)(i18n.decision?.[nouvelleDecision]);
        }

        if (administre && administre.identite_grade_nom_prenom && poste && poste.libelleGroupe) {
            msgConfirmation +=
                " entre l'administré\n      " + administre.identite_grade_nom_prenom + '\net le poste\n      ' + poste.libelleGroupe + '\n';
        } else if (administre && administre.identite_grade_nom_prenom) {
            msgConfirmation += " pour l'administré " + administre.identite_grade_nom_prenom;
        } else if (poste && poste.libelleGroupe) {
            msgConfirmation += ' pour le poste ' + poste.libelleGroupe;
        }

        msgConfirmation += ' ?';
        try {
            //TODO plus besoin de charger l'admin et le poste, récupérer la donnée décision mappée pour AG Grid
            let supprimerAncien;
            if (poste && administre) {
                let posteOfAdministre = administre.decision_posteId;
                let administreOfPoste = poste.decision_administreId;

                if (posteOfAdministre && posteOfAdministre !== poste.id) {
                    supprimerAncien = true;
                    msgConfirmation += '\n\nATTENTION ! Cet administré est déjà lié par une décision avec un autre poste. Cette liaison sera annulée.';
                }

                // On s'assure que le poste n'est pas déjà lié à un autre administré, sinon on ajoute un avertissement
                if (administreOfPoste && administreOfPoste !== administre.id) {
                    supprimerAncien = true;
                    msgConfirmation += '\n\nATTENTION ! Ce poste est déjà lié par une décision avec un autre administré. Cette liaison sera annulée.';
                }
            }

            //TODO afficher le message de confirmation via une modale avec les boutons "OK" et "Annuler" (donc à gérer en asynchrone !)
            if (!sansConfirmation && !window.confirm(msgConfirmation)) {
                toast.info('Opération annulée.');
                onCancelOrError();
                return false;
            }

            // Si annulation de la décision et que la décision actuelle est liée à un OMI, on demande à l'utilisateur à quelle décision il faut repasser
            if (nouvelleDecision === DECISIONS.AUCUNE && (decisionActuelle === DECISIONS.OMI_ACTIVE || decisionActuelle === DECISIONS.OMI_EN_COURS)) {
                //TODO demander à l'utilisateur quelle nouvelle décision il veut pour le couple administré/poste
                //(en attendant d'avoir câblé ça via une pop-in dédiée, on ne fait rien donc on repasse à DECISIONS.AUCUNE = on annule la décision actuelle)
            }
            const decisionManager = managers.decisions;
            if (nouvelleDecision !== DECISIONS.AUCUNE) {
                const annee = this.appConfig.PAMSelectionne;
                const params = {};
                annee && (params.pam__in = annee);
                try {
                    await (administre.decision_decision && !supprimerAncien
                        ? decisionManager.update(administre.id_pam, { de_decision: nouvelleDecision })
                        : decisionManager.decide(administre.id, poste.id, nouvelleDecision, supprimerAncien, params));
                    toast.success('La décision a bien été enregistrée.');
                    return true;
                } catch (e) {
                    console.error(e);
                    toast.error("Une erreur est survenue lors de l'enregistrement du statut de décision. Veuillez contacter un administrateur.", { autoClose: false });
                    onCancelOrError();
                    return false;
                }
            } else {
                let administreId = administre ? administre.id_pam : poste ? poste.decisions_administre_id_pam : null;
                if (administreId) {
                    await decisionManager.destroy(administreId);
                    toast.success('La décision a bien été annulée.');
                    return true;
                } else {
                    toast.error("Erreur de chargement de l'administré ou du poste", { autoClose: false });
                    console.error(reason);
                    onCancelOrError();
                    return false;
                }
            }
        } catch (reason) {
            toast.error("Erreur de chargement de l'administré ou du poste", { autoClose: false });
            console.error(reason);
            onCancelOrError();
            return false;
        }
    }

    /**
     * Lance les calculs (ranking + matching) pour le PAM en cours, sur le sous-vivier actuellement sélectionné.
     *
     * @param {import('../jsdoc/api').IdSousVivierApi} sousVivierId - Sous-vivier sur lequel lancer les calculs
     * @returns {boolean} indique si le calcul a été lancé avec succès
     */
    lanceCalculs(sousVivierId, pamId) {
        try {
            // TODO actuellement il n'y a pas d'await ici
            // this.appConfig.managers.decisions.lanceCalculs(sousVivierId, pamId);
            this.appConfig.managers.decisions.lanceCalculs(sousVivierId, pamId)
                .then((response) => {
                    if (response.data.info){
                        toast.warning(response.data.info, { autoClose: true })
                    }
                    toast.success('Scoring et ranking terminés !', { autoClose: true })
                })
                .catch((reason) => {
                    console.error(reason);
                    })
            toast.info('Les calculs de scoring sur le sous-vivier ont bien été lancés');
            return true;
        } catch (reason) {
            console.error('reason',reason);
            toast.error('Erreur de lancement des calculs', { autoClose: true });
            //TODO gérer les différents cas d'erreurs (ex : calcul déjà en cours...)
            return false;
        }
    }

    /**
     * Lance les calculs (ranking + matching) pour le PAM en cours, sur un sous-ensemble d'administrés et de postes sélectionnés.
     *
     * @param {import('../jsdoc/api').IdAdministreApi} administreId - Id administre
     * @param {import('../jsdoc/api').IdPosteApi} posteId - Id du poste
     * @param {import('../jsdoc/api').IdSousVivierApi} sousVivierId
     * @returns {boolean} indique si le calcul a été lancé avec succès
     */
    lanceCalculSelectif(sousVivierId, administreId, posteId, pamId) {
        try {
            // TODO actuellement il n'y a pas d'await ici
            // this.appConfig.managers.decisions.lanceCalculs(sousVivierId, pamId);
            this.appConfig.managers.decisions.lanceCalculSelectif(sousVivierId, administreId, posteId, pamId)
                .then((response) => {
                    if (response.data.info){
                        toast.warning(response.data.info, { autoClose: true })
                    }
                    toast.success('Scoring sélectifs et ranking terminés !', { autoClose: true })
                })
                .catch((reason) => {
                    console.error(reason);
                    })
            toast.info('Les calculs de scoring sur le sous-vivier ont bien été lancés');
            return true;
        } catch (reason) {
            console.error(reason);
            toast.error('Erreur de lancement des calculs', { autoClose: true });
            //TODO gérer les différents cas d'erreurs (ex : calcul déjà en cours...)
            return false;
        }
    }

    /**
     * Arrêter les calculs pour le PAM en cours, sur le sous-vivier actuellement sélectionné.
     *
     * @param {import('../jsdoc/api').IdSousVivierApi} sousVivierId - Sous-vivier sur lequel arreter les calculs
     * @returns {boolean} indique si le calcul a été arrêté avec succès
     */
    arretCalculs(sousVivierId, pamId) {
        try {
            // TODO actuellement il n'y a pas d'await ici
            this.appConfig.managers.decisions.arretCalcul(sousVivierId, pamId);
            console.log('latence');
            toast.info('Les calculs de scoring sur le sous-vivier ont bien été arrêtés');
            return true;
        } catch (reason) {
            console.error(reason);
            toast.error('Erreur de arreter les calculs', { autoClose: false });
            //TODO gérer les différents cas d'erreurs (ex : calcul déjà en cours...)
            return false;
        }
    }

    /**
     * Arrêter les calculs pour le PAM en cours, sur un sous-ensemble d'administrés et de postes sélectionnés.
     *
     * @param {import('../jsdoc/api').IdAdministreApi} administreId - Id administre
     * @param {import('../jsdoc/api').IdPosteApi} posteId - Id du poste
     * @returns {boolean} indique si le calcul a été arrêté avec succès
     */
    arretCalculSelectif(administreId, posteId) {
        try {
            // TODO actuellement il n'y a pas d'await ici
            this.appConfig.managers.decisions.arretCalcul(administreId, posteId);
            console.log('latence');
            toast.info('Les calculs de scoring sur le sous-ensemble ont bien été arrêtés');
            return true;
        } catch (reason) {
            console.error(reason);
            toast.error('Erreur de arreter les calculs', { autoClose: false });
            //TODO gérer les différents cas d'erreurs (ex : calcul déjà en cours...)
            return false;
        }
    }

}
