import 'ag-grid-community/dist/styles/ag-grid.css';
import 'ag-grid-community/dist/styles/ag-theme-balham.css';
import 'ag-grid-enterprise';
import { observer } from 'mobx-react';
import React, { useContext, useEffect, useState } from 'react';
import { useHistory } from 'react-router-dom';
import { cssMenu } from '../../../constantes/classes-css';
import { ADMINISTRES, NAVIGATION, POSTES } from '../../../constantes/constantes';
import { debounce } from '../../../helpers/misc-helpers';
import AGLocaleText from '../../../i18n/aggrid-locale-fr';
import AppConfigStore, { AppConfigContext } from '../../../stores/AppConfigStore';
import InformationsFiltres from '../../Commun/InformationsFiltres';
import { commonAGGridColumnTypes } from '../../Commun/listes/commonAGGridColumnTypes';
import { commonAGGridFrameworkComponents } from '../../Commun/listes/commonAGGridFrameworkComponents';
import CustomAgGridReact from '../../Commun/listes/CustomAgGridReact';
import { onCellValueChanged } from '../../Commun/listes/fonctionsEtCallbacksAgGrid';
import {
    ajouteElementsCommunsAdministreAMenuContextuel, ajouteElementsCommunsAMenuContextuel, ajouteElementsCommunsPosteAMenuContextuel, ensureVisibleFirstSelectedRow, supprimeSeparateursSurnumerairesMenuContextuel
} from '../../Commun/listes/helpers/listes-ag-grid-helpers';

/**
 * Composant permettant d'afficher une liste de postes ou d'administrés à traiter pour la vue d'aide à la décision.
 *
 * @component
 * @param {array} props.columnDefs - Les champs pour construire l'Ag Grid
 * @param {object} props.data - Les données pour remplir l'Ag Grid
 * @param {number} props.nbItems - Le nombre total d'éléments dans la liste
 * @param {string} props.title - Le titre du tableau Ag Grid
 * @param {string} props.label - Le label associé au tableau
 *
 * @example
 * return (
 * <ListeGestionDecision fields={postesFields} data={rowData} nbItems={nbItems} title="Postes" itemLabel="poste" itemsLabel="postes"/>
 * )
 */

const ListeGestionDecision = observer((props) => {
    const gridId = 'LGD_' + props.context.groupeType;
    /** @type {AppConfigStore} */
    const appConfig = useContext(AppConfigContext);

    /* States for using Grid Api */
    const [gridApi, setGridApi] = useState(null);
    const [filterChanged, setFilterChanged] = useState(false);
    const [nbFiltered, setNbFiltered] = useState(0);
    const [isFiltered, setIsFiltered] = useState(false);
    const [isFilterReset, setIsFilterReset] = useState(false);

    const history = useHistory();

    /**
     * Met à jour la ligne sélectionnée dans la liste.
     */
    const setSelectedAGGridRow = (api) => {
        switch (props.context.groupeType) {
            case ADMINISTRES:
                if (appConfig.hasSelectedAdministreDecision) {
                    api.forEachNode(function (node) {
                        node.setSelected(node?.data?.id === appConfig.selectedAdministreDecision.id);
                    });
                }
                break;

            case POSTES:
                if (appConfig.hasSelectedPosteDecision) {
                    api.forEachNode(function (node) {
                        node.setSelected(node?.data?.id === appConfig.selectedPosteDecision.id);
                    });
                }
                break;
        }
    };

    /**
     * Callback permettant d'effectuer des actions sur la ligne sélectionnée
     *
     * @void - Pour le moment rien du tout
     */
    const onSelectionChanged = debounce((e) => {
        const selectedRows = e.api.getSelectedRows();
        switch (props.context.groupeType) {
            case ADMINISTRES:
                appConfig.setSelectedAdministreDecision(selectedRows[0]);
                break;
            case POSTES:
                appConfig.setSelectedPosteDecision(selectedRows[0]);
                break;
        }
    }, 200);

    const showFirstSelectedRow = debounce((e) => {
        if (props.context.groupeType === ADMINISTRES && appConfig.hasSelectedAdministreDecision) {
            ensureVisibleFirstSelectedRow([appConfig.selectedAdministreDecision], e.api);
        } else if (props.context.groupeType === POSTES && appConfig.hasSelectedPosteDecision) {
            ensureVisibleFirstSelectedRow([appConfig.selectedPosteDecision], e.api);
        }
    }, 200);

    /**
     * Options de la grille
     */
    //TODO factoriser les options communes à toutes les liste d'Ogure NG dans CustomAgGridReact
    const gridOptions = {
        debug: false,
        groupHeaderHeight: 35,
        headerHeight: 40,
        enableBrowserTooltips: true,
        animateRows: true,
        columnTypes: commonAGGridColumnTypes,
        context: props.context,
        defaultColDef: {
            resizable: true,
            sortable: true,
            filter: true,
            editable: false,
            enableRowGroup: true,
            menuTabs: ['filterMenuTab', 'generalMenuTab']
        },
        defaultColGroupDef: { autoHeight: true },
        frameworkComponents: commonAGGridFrameworkComponents,
        localeText: AGLocaleText,
        onFilterChanged: () => setFilterChanged(true),
        onGridReady: (params) => {
            setGridApi(params.api);
            setSelectedAGGridRow(params.api);
        },
        onFirstDataRendered: showFirstSelectedRow,
        onComponentStateChanged: (params) => {
            // Nécessaire car onGridReady n'est pas *systématiquement* appelé quand ce composant est mis à jour ?!
            setSelectedAGGridRow(params.api);
        },
        onCellValueChanged: (params) => {
            onCellValueChanged(params, props.context.groupeType, appConfig);
            onSelectionChanged(params); // On force la MAJ de la sélection immédiatement pour qu'elle tienne compte des nouvelles valeurs
        },
        onSelectionChanged: onSelectionChanged,
        rowSelection: 'single',
        popupParent: document.querySelector('body'),
        getContextMenuItems: (params) => getContextMenuItems(params),
        getRowNodeId: (data) => data.id
    };

    useEffect(() => {
        if (filterChanged) {
            if (!isFilterReset) {
                if (Object.keys(gridApi.getFilterModel()).length === 0) {
                    setIsFiltered(false);
                } else {
                    setIsFiltered(true);
                    setNbFiltered(gridApi.getDisplayedRowCount());
                }
            } else {
                setIsFilterReset(false);
            }
        }
        setFilterChanged(false);
    }, [filterChanged]);

    useEffect(() => {
        // RAZ des filtres dans les données ont changé
        if (isFiltered) {
            setIsFiltered(false);
            setIsFilterReset(false);
            setNbFiltered(0);
        }
    }, [props.data]);

    /**
     * Fonction permettant de définir les éléments du menu contextuel (clic droit)
     *
     * @param {CheckboxSelectionCallbackParams} params - Paramètres concernant la colonne
     * @return - Renvoie les items du menu contextuel
     */
    const getContextMenuItems = (params) => {
        if (params.node.group) return;

        const menuItems = [];

        if (props.context.groupeType === ADMINISTRES) {
            // --- Eléments spécifiques aux administrés
            addContextMenuItemsAdministres(menuItems, params);
        } else if (props.context.groupeType === POSTES) {
            // --- Eléments spécifiques aux postes
            addContextMenuItemsPostes(menuItems, params);
        }

        ajouteElementsCommunsAMenuContextuel(menuItems);

        supprimeSeparateursSurnumerairesMenuContextuel(menuItems);

        return menuItems;
    };

    /**
     * Ajoute aux éléments du menu ceux spécifiques à la liste des administrés.
     *
     * @param {Array.<Object>} menuItems - Liste des éléments de menus à compléter
     * @param {*} params - Paramètre d'appel à getContextMenuItems
     */
    function addContextMenuItemsAdministres(menuItems, params) {
        const administreDataNode = params.node?.data;

        // Action : fiche détaillée administré (toujours proposée)
        ajouteElementsCommunsAdministreAMenuContextuel(menuItems, administreDataNode, appConfig);

        // Actions : Voir cet administré dans une autre vue
        menuItems.push({
            name: 'Localiser cet administré dans la vue "Mon périmètre"',
            cssClasses: [cssMenu.svgIcon, 'localiser'],
            action: () => {
                appConfig.setSelectedAdministresPerimetre([administreDataNode]);
                if (appConfig.typeVuePerimetre === POSTES) {
                    appConfig.setTypeVuePerimetre(ADMINISTRES);
                }
                history.push(NAVIGATION.PERIMETRE);
            }
        });
    }

    /**
     * Ajoute aux éléments du menu ceux spécifiques à la liste des postes.
     *
     * @param {Array.<Object>} menuItems - Liste des éléments de menus à compléter
     * @param {*} params - Paramètre d'appel à getContextMenuItems
     */
    function addContextMenuItemsPostes(menuItems, params) {
        const posteDataNode = params.node?.data;

        ajouteElementsCommunsPosteAMenuContextuel(menuItems, posteDataNode, appConfig);

        // Actions : Voir ce poste dans une autre vue
        menuItems.push({
            name: 'Localiser ce poste dans la vue "Mon périmètre"',
            cssClasses: [cssMenu.svgIcon, 'localiser'],
            action: () => {
                appConfig.setSelectedPostesPerimetreEtITD([posteDataNode]);
                if (appConfig.typeVuePerimetre === ADMINISTRES) {
                    appConfig.setTypeVuePerimetre(POSTES);
                }
                history.push(NAVIGATION.PERIMETRE);
            }
        });
    }

    return (
        <div className="flex-grow-1 flex-shrink-1 w-100">
            <div className="container-fluid h-100">
                <div className="ag-theme-balham" style={{ height: 'calc(100% - 5em)' }}>
                    <div className={'d-flex flex-row align-items-center px-0 d-inline pt-2'}>
                        <h3 style={{ fontSize: '1.2rem', marginBottom: '0' }}>{props.title}</h3>
                    </div>
                    {props.data && (
                        <InformationsFiltres
                            nbItems={props.nbItems}
                            itemLabel={props.itemLabel}
                            itemsLabel={props.itemsLabel}
                            nbFiltered={nbFiltered}
                            isFiltered={isFiltered}
                            setIsFilterReset={setIsFilterReset}
                            setIsFiltered={setIsFiltered}
                            nbSelected={0}
                            nbSelectedVisible={0}
                            gridApi={gridApi}
                        />
                    )}
                    <CustomAgGridReact
                        id={gridId}
                        rowData={props.data}
                        gridOptions={gridOptions}
                        columnDefs={props.columnDefs}
                        persistencePrefix={appConfig.utilisateurConnecte?.id}
                    />
                </div>
            </div>
        </div>
    );
});

export default ListeGestionDecision;
