/*
 * Fonctions utilitaires de manipulation des données métiers dans AG Grid.
 */

import { COMPETENCES_SEPARATEUR, DEPARTEMENTS_SOUHAITES_SEPARATEUR, ZONES_SEPARATEUR } from '../../../../constantes/constantes';
import i18n from '../../../../i18n/i18n';

/**
 * Librairie de fonctions utilitaires pour la manipulation des données des listes AG Grid d'Ogure NG.
 *
 * @module
 */

/**
 * Renvoie une callback de comparaison de marques, fonctionnant dans le contexte (données de référence) fourni.
 *
 * @param {?import('../../../../jsdoc/types').DonneesReference} refs - toutes les données de référence
 * @returns {function} callback de comparaison entre 2 marques
 */
export function createMarquesComparator(refs) {
    return (m1, m2) => {
        const marque1 = refs?.marquesById?.get(m1);
        const marque2 = refs?.marquesById?.get(m2);
        if (!marque1 && !marque2) {
            return marques1 ? 1 : marques2 ? -1 : 0;
        }

        const groupeMarque1 = refs?.groupesMarquesById?.get(marque1.groupeMarquesId);
        const groupeMarque2 = refs?.groupesMarquesById?.get(marque2.groupeMarquesId);
        if (!groupeMarque1 && !groupeMarque2) {
            return groupeMarque1 ? 1 : groupeMarque2 ? -1 : 0;
        }

        return groupeMarque1.ordre - groupeMarque2.ordre || marque1.ordre - marque2.ordre;
    };
}

/**
 * Renvoie un domaine.
 *
 * @param {?import('../../../../jsdoc/types').DonneesReference} refs - toutes les données de référence
 * @param {*} domaineId - Id du domaine
 * @param {?Object} domaine ou null
 */
export const getDomaine = (refs, domaineId) => refs?.domainesById?.get(domaineId) ?? null;

/**
 * Renvoie une propriété d'un domaine.
 *
 * @param {?import('../../../../jsdoc/types').DonneesReference} refs - toutes les données de référence
 * @param {*} domaineId - Id du domaine
 * @param {*} propName - Nom de la propriété ("code" par défaut)
 * @param {*} defaultValEmptyProp - Valeur par défaut si la propriété est vide (i18n.global.donnees.vide par défaut)
 * @param {*} defaultValNonExistant - Valeur par défaut si le domaine n'existe pas (null par défaut)
 */
// FIXME PIERRIC: comportement spécial
export function getDomaineProperty(
    refs,
    domaineId,
    propName = 'code',
    defaultValEmptyProp = i18n.global.donnees.vide,
    defaultValNonExistant = i18n.global.donnees.vide
) {
    const domaine = getDomaine(refs, domaineId);
    // if (!domaine) {
    //     return defaultValNonExistant;
    // }

    return domaine ? domaine[propName] || defaultValEmptyProp : defaultValNonExistant;
}

/**
 * Renvoie une filière.
 *
 * @param {?import('../../../../jsdoc/types').DonneesReference} refs - toutes les données de référence
 * @param {*} filiereId - Id de la filière
 * @returns {?Object} filière ou null
 */
export const getFiliere = (refs, filiereId) => refs?.filieresById?.get(filiereId) ?? null;

/**
 * Renvoie une compétence d'id donné.
 *
 * @param {?import('../../../../jsdoc/types').DonneesReference} refs - toutes les données de référence
 * @param {*} competenceId - Id de la competence
 * @returns {?Object} compétence ou null
 */
export const getCompetence = (refs, competenceId) => refs?.competencesById?.get(competenceId) ?? null;

/**
 * Renvoie une liste de compétences d'id donnés.
 *
 * @param {?import('../../../../jsdoc/types').DonneesReference} refs - toutes les données de référence
 * @param {*} competenceIds - Id des compétences
 * @returns {Object[]} compétences
 */
export function getCompetences(refs, competenceIds) {
    const compIds = typeof competenceIds === 'string' ? competenceIds.split(COMPETENCES_SEPARATEUR) : competenceIds;
    return compIds?.map((id) => getCompetence(refs, id)).filter((val) => !!val) ?? [];
}

/**
 * Renvoie un département d'id donné.
 *
 * @param {?import('../../../../jsdoc/types').DonneesReference} refs - toutes les données de référence
 * @param {*} departementId - Id du département
 * @returns {?Object} déplartement ou null
 */
export const getDepartement = (refs, departementId) => refs?.departementsById?.get(departementId) ?? null;

/**
 * Renvoie une liste de zones de libéllé donnés.
 *
 * @param {*} competenceIds - Libéllé des zones
 */
export function getZones(ZonesLib) {
    const zoneLibs = typeof ZonesLib === 'string' ? ZonesLib.split(ZONES_SEPARATEUR) : ZonesLib;
    return zoneLibs ? zoneLibs : [];
}

/**
 * Renvoie une liste de départements d'id donnés.
 *
 * @param {?import('../../../../jsdoc/types').DonneesReference} refs - toutes les données de référence
 * @param {*} departementsIds - Ids des départements
 * @returns {Object[]} départements
 */
export function getDepartements(refs, departementsIds) {
    const deptIds = typeof departementsIds === 'string' ? departementsIds.split(DEPARTEMENTS_SOUHAITES_SEPARATEUR) : departementsIds;
    return deptIds?.map((id) => getDepartement(refs, id)).filter((val) => !!val) ?? [];
}

/**
 * Renvoie une propriété d'une filière.
 *
 * @param {?import('../../../../jsdoc/types').DonneesReference} refs - toutes les données de référence
 * @param {*} filiereId - Id de la filière
 * @param {*} propName - Nom de la propriété ("code" par défaut)
 * @param {*} defaultValEmptyProp - Valeur par défaut si la propriété est vide (i18n.global.donnees.vide par défaut)
 * @param {*} defaultValNonExistant - Valeur par défaut si le filiere n'existe pas (null par défaut)
 */
export function getFiliereProperty(
    refs,
    filiereId,
    propName = 'code',
    defaultValEmptyProp = i18n.global.donnees.vide,
    defaultValNonExistant = i18n.global.donnees.erreur
) {
    const filiere = getFiliere(refs, filiereId);
    if (!filiere) {
        return defaultValNonExistant;
    }

    return filiere ? filiere[propName] || defaultValEmptyProp : defaultValNonExistant;
}

/**
 * Renvoie un avis sur un administré à partir de son code.
 *
 * @param {?import('../../../../jsdoc/types').DonneesReference} refs - toutes les données de référence
 * @param {string} code - code de l'avis
 * @returns {Object} avis ou undefined
 */
export const getAvisAdministre = (refs, code) => refs?.avisAdministreById?.get(code);

/**
 * Renvoie un avis sur un poste à partir de son code.
 *
 * @param {?import('../../../../jsdoc/types').DonneesReference} refs - toutes les données de référence
 * @param {string} code - code de l'avis
 * @returns {Object} avis ou undefined
 */
export const getAvisPoste = (refs, code) => refs?.avisPosteById?.get(code);

/**
 * Indique s'il est possible d'affecter un administré à ce poste.
 *
 * @param {?import('../../../../jsdoc/types').DonneesReference} refs - toutes les données de référence
 * @param {Object} poste - Données concernant le poste
 * @returns {boolean} true si l'affectation est possible
 */
export function isPosteAffectable(refs, poste) {
    return !!(!poste?.decisions?.trim() && getAvisPoste(refs, poste?.priorite_drhat)?.affectationManuellePossible);
}

/**
 * Calcule le nombre total d'administrés affectables à un poste (= somme des avis avec affectationManuellePossible)
 *
 * @param {?import('../../../../jsdoc/types').DonneesReference} refs - toutes les données de référence
 * @param {Object} poste - Données concernant le poste
 * @returns {number}  nombre total d'administrés affectables au poste
 */
export function getNbAdministresAffectables(refs, poste) {
    if (!poste) return 0;
    return (refs?.avisPoste ?? [])
        .filter((ap) => ap.affectationManuellePossible)
        .reduce((somme, ap) => somme + parseInt(poste['p_nb_' + ap.code.toLowerCase()] || 0, 10), 0);
}

/**
 * Calcule le nombre total d'administrés affectés à un poste (= somme des décisions sur ce poste)
 *
 * @param {?import('../../../../jsdoc/types').DonneesReference} refs - toutes les données de référence
 * @param {Object} poste - Données concernant le poste
 * @returns {number} nombre total d'administrés affectés au poste
 */
export function getNbAdministresAffectes(refs, poste) {
    if (!poste) return 0;
    return [...refs?.decisionsById?.keys()].reduce((somme, decision) => somme + parseInt(poste['p_nb_' + decision.toLowerCase()] || 0, 10), 0);
}

/**
 * Calcule le nombre total d'administrés encore affectables à un poste (= nombre total affectablse - nb déjà affecté)
 *
 * @param {?import('../../../../jsdoc/types').DonneesReference} refs - toutes les données de référence
 * @param {Object} poste - Données concernant le poste
 * @returns {number} nombre total d'administrés affectés au poste
 */
export function getNbAdministresEncoreAffectables(refs, poste) {
    return getNbAdministresAffectables(refs, poste) - getNbAdministresAffectes(refs, poste);
}
