const _ = require('lodash');
require('dotenv').config();
module.exports = {


    friendlyName: 'Create',


    description: 'Create Attribution note moyenne!',


    inputs: {
        /*codeMatiere: {
            type: 'string',
            required: true
        },

        codeEcole: {
            type: 'string',
            required: true
        },
        matricule: {
            type: 'string',
            required: true
        },
        codeClasse: {
            type: 'string',
            required: true
        },

        libelleCourt: {
            type: 'string',
        },

        libelleLong: {
            type: 'string',
        },
        typeNote: {
            type: 'string',
        },

        note: {
            type: 'string',
        },
        moyenne: {
            type: 'string',
        },
        moyenneCoef: {
            type: 'string',
        },

        totalMoyenne: {
            type: 'string',
        },

        rang: {
            type: 'string',
        },

        forteMoyenne: {
            type: 'string',
        },
        faibleMoyenne: {
            type: 'string',
        },

        moyenneClasse: {
            type: 'string',
        },

        appreciationProf: {
            type: 'string',
        },

        anneeScolaire: {
            type: 'string',
        },

        coef: {
            type: 'string',
        },

        trimSem: {
            type: 'string',
        },

        codMoy: {
            type: 'string',
        },*/


        listeElementAjout: {
            type: 'ref'
        },

        logiUsername: {
            type: 'string',
            require: true

        },
        key: {
            type: 'string',
            require: true

        },
        logiPassword: {
            type: 'string',
            require: true

        },


    },


    exits: {
        notFound: {
            statusCode: 404
        },
    },


    fn: async function (inputs, exits) {

        //console.log("INPUTS 1", inputs)

        // TOKEN VERIFY
        let user = await Utilisateurs.find({ login: inputs.logiUsername, codeUser: inputs.logiPassword }).then(_.first)
        if (!user) {
            return exits.notFound('Utilisateur non trouvé')
        }
        //console.log("INPUTS 2", inputs)

        let keyVerify = process.env.KEYVERIFY
        //
        if (keyVerify !== inputs.key) {
            return exits.notFound({ message: "Token non valide" })
        }


        ///////////////////


        const successes = [];
        const failures = [];
        const existings = []; // Tableau pour stocker les éléments qui existent déjà
        const now = Date.now(); // Obtenir le timestamp actuel pour createdAt

        try {
            // --- 2. Rechercher toutes les attributions de note moyenne existantes ---
            // Cette étape prépare les clés uniques à rechercher dans la base de données.
            const keysToFind = inputs.listeElementAjout.map(item => ({
                codeMatiere: item.codeMatiere,
                codeEcole: item.codeEcole,
                codeClasse: item.codeClasse,
                matricule: item.matricule,
                typeNote: item.typeNote,
                anneeScolaire: item.anneeScolaire,
                trimSem: item.trimSem,
                codMoy: item.codMoy
            }));

            // Effectue une seule requête pour récupérer tous les enregistrements d'attributions
            // existants qui pourraient correspondre aux éléments à ajouter.
            // `_.keyBy` transforme le résultat en un objet pour une recherche rapide des doublons.
            const existingAttributions = await AttributionNoteMoyenne.find({
                or: keysToFind
            }).then(attribs => _.keyBy(attribs, attr =>
                `${attr.codeMatiere}-${attr.codeEcole}-${attr.codeClasse}-${attr.matricule}-${attr.typeNote}-${attr.anneeScolaire}-${attr.trimSem}-${attr.codMoy}`)
            );

            // --- 3. Traiter les nouvelles attributions de note moyenne ---
            // Cette boucle détermine quels éléments sont nouveaux et lesquels sont des doublons.
            const attributionsToCreate = [];

            for (const item of inputs.listeElementAjout) {
                const key = `${item.codeMatiere}-${item.codeEcole}-${item.codeClasse}-${item.matricule}-${item.typeNote}-${item.anneeScolaire}-${item.trimSem}-${item.codMoy}`;
                if (!existingAttributions[key]) {
                    // Si la clé n'existe pas, c'est une nouvelle attribution à créer.
                    // Ajouter le champ createdAt si votre modèle AttributionNoteMoyenne le gère
                    attributionsToCreate.push({ ...item });
                } else {
                    // Si l'attribution existe déjà, on l'ajoute au tableau 'existings'
                    existings.push(existingAttributions[key]);
                    /*existings.push({
                        id: key,
                        message: 'Cette attribution de note moyenne existe déjà et n\'a pas été modifiée.',
                        data: existingAttributions[key] // Vous pouvez inclure les données de l'enregistrement existant si nécessaire
                    });*/
                }
            }

            // --- 4. Validation préventive + Transaction optimisée pour permettre l'enregistrement partiel ---
            // Approche hybride : validation préventive + traitement en lot avec fallback individuel
            if (attributionsToCreate.length > 0) {
                // 1. Validation préventive de tous les éléments
                const validItems = [];
                const invalidItems = [];

                for (const item of attributionsToCreate) {
                    if (item.codeMatiere && item.codeEcole && item.codeClasse && item.matricule && item.anneeScolaire && item.trimSem) {
                        validItems.push(item);
                    } else {
                        const missingFields = [];
                        if (!item.codeMatiere) missingFields.push('codeMatiere');
                        if (!item.codeEcole) missingFields.push('codeEcole');
                        if (!item.codeClasse) missingFields.push('codeClasse');
                        if (!item.matricule) missingFields.push('matricule');
                        if (!item.anneeScolaire) missingFields.push('anneeScolaire');
                        if (!item.trimSem) missingFields.push('trimSem');

                        invalidItems.push({
                            id: `${item.codeMatiere || 'N/A'}-${item.codeEcole || 'N/A'}-${item.codeClasse || 'N/A'}-${item.matricule || 'N/A'}-${item.anneeScolaire || 'N/A'}-${item.trimSem || 'N/A'}`,
                            message: `Champs requis manquants : ${missingFields.join(', ')}`,
                            item: item
                        });
                    }
                }

                // 2. Traitement en lot des éléments valides
                if (validItems.length > 0) {
                    try {
                        const createdRecords = await AttributionNoteMoyenne.createEach(validItems).fetch();
                        successes.push(...createdRecords);
                    } catch (createError) {
                        sails.log.error('Échec de la création en lot, passage au traitement individuel:', createError);

                        // En cas d'échec, traiter individuellement
                        for (const item of validItems) {
                            try {
                                const createdRecord = await AttributionNoteMoyenne.create(item).fetch();
                                successes.push(createdRecord);
                            } catch (individualError) {
                                sails.log.error(`Erreur lors de la création individuelle de l'attribution de note moyenne ${item.codeMatiere}:`, individualError);

                                // Analyser l'erreur pour donner un message plus précis
                                let errorMessage = 'Erreur lors de la création';
                                if (individualError.code === 'E_INVALID_NEW_RECORDS') {
                                    errorMessage = 'Données invalides pour la création';
                                } else if (individualError.code === 'E_UNIQUE') {
                                    errorMessage = 'Violation de contrainte d\'unicité';
                                } else if (individualError.code === 'E_FOREIGN_KEY') {
                                    errorMessage = 'Référence invalide (matière, classe, école ou élève inexistant)';
                                }

                                failures.push({
                                    id: `${item.codeMatiere || 'N/A'}-${item.codeEcole || 'N/A'}-${item.codeClasse || 'N/A'}-${item.matricule || 'N/A'}-${item.anneeScolaire || 'N/A'}-${item.trimSem || 'N/A'}`,
                                    message: errorMessage,
                                    error: individualError.message,
                                    item: item
                                });
                            }
                        }
                    }
                }

                // 3. Ajouter les éléments invalides aux échecs
                failures.push(...invalidItems);
            }

            // --- 5. Déterminer le statut global et préparer la réponse ---
            // Évalue les résultats pour fournir un statut global de l'opération.
            let overallStatus = 'success';
            let message = 'Le traitement par lot des attributions de note moyenne est terminé.';

            if (failures.length > 0 && successes.length === 0 && existings.length === 0) {
                overallStatus = 'failure';
                message = 'Le traitement par lot des attributions de note moyenne a échoué pour tous les éléments fournis.';
            } else if (successes.length > 0 && failures.length === 0 && existings.length === 0) {
                overallStatus = 'success';
                message = 'Toutes les nouvelles attributions de note moyenne ont été ajoutées avec succès.';
            } else if (inputs.listeElementAjout.length === 0) {
                message = 'Aucune attribution de note moyenne fournie pour le traitement.';
            } else {
                // Combinaison de succès, échecs et/ou existants
                overallStatus = 'partial_success';
                message = 'Le traitement par lot des attributions de note moyenne est terminé avec des succès, des échecs et/ou des éléments existants.';
            }


            // --- 6. Envoi d'une notification push unique par parent (fin de requête) ---
            try {
                if (successes.length > 0) {
                    const matricules = _.uniq(successes.map(r => r.matricule).filter(Boolean));
                    const ecoles = _.uniq(successes.map(r => r.codeEcole).filter(Boolean));
                    if (matricules.length > 0) {
                        const filiations = await Filiation.find({ matricule: { in: matricules }, codeEcole: { in: ecoles } });
                        const codeParents = _.uniq(filiations.map(f => f.codeParent).filter(Boolean));
                        if (codeParents.length > 0) {
                            const tokens = await PushToken.find({ codeUser: { in: codeParents } });
                            const tokenList = _.uniq(tokens.map(t => t.fcmToken).filter(Boolean));
                            if (tokenList.length > 0) {
                                const title = 'Attribution de moyennes mise à jour';
                                const body = 'Les moyennes de votre enfant ont été mises à jour.';
                                const data = { route: '/notifications', type: 'moyennes_update', createdCount: String(successes.length) };
                                await sails.helpers.sendFcm.with({ tokens: tokenList, title, body, data });
                            }
                        }
                    }
                }
            } catch (notifyErr) {
                sails.log.warn('Envoi FCM (attribution note moyenne) échoué:', notifyErr.message || notifyErr);
            }

            // --- 7. Renvoyer la réponse ---
            // Retourne un objet JSON détaillé pour informer l'appelant.
            return exits.success({
                status: overallStatus,
                message: message,
                successes: successes,
                failures: failures,
                existings: existings, // Inclure le tableau des éléments existants dans la réponse
                createdAt: now,
            });

        } catch (err) {
            sails.log.error('Error processing batch create average note attributions:', err);
            // Gère toute erreur inattendue qui pourrait survenir.
            return exits.serverError({
                status: 'error',
                message: 'Une erreur interne du serveur est survenue lors du traitement par lot des attributions de note moyenne.',
                error: err.message,
                createdAt: now,
            });
        }
    }


};
