/**
 * process-payment.js
 *
 * @description :: Traiter un paiement pour un abonnement
 * @help        :: Voir http://sailsjs.com/#!/documentation/concepts/Controllers
 */

module.exports = {
    friendlyName: 'Traiter un paiement d\'abonnement',

    description: 'Traiter un paiement pour un abonnement existant',

    inputs: {
        codeAbonnement: {
            type: 'string',
            required: true,
            description: 'Code de l\'abonnement'
        },
        methodePaiement: {
            type: 'string',
            required: true,
            isIn: ['mobile_money', 'carte_bancaire', 'virement', 'especes', 'gratuit'],
            description: 'Méthode de paiement'
        },
        montant: {
            type: 'number',
            required: true,
            description: 'Montant payé'
        },
        devise: {
            type: 'string',
            required: true,
            description: 'Devise du paiement'
        },
        referencePaiement: {
            type: 'string',
            allowNull: true,
            description: 'Référence de paiement externe'
        },
        operateur: {
            type: 'string',
            allowNull: true,
            description: 'Opérateur de paiement (pour mobile money)'
        },
        numeroTelephone: {
            type: 'string',
            allowNull: true,
            description: 'Numéro de téléphone utilisé pour le paiement'
        },
        fraisTransaction: {
            type: 'number',
            defaultsTo: 0,
            description: 'Frais de transaction'
        },
        description: {
            type: 'string',
            allowNull: true,
            description: 'Description du paiement'
        },
        donneesTechniques: {
            type: 'json',
            defaultsTo: {},
            description: 'Données techniques du paiement'
        }
    },

    exits: {
        success: {
            description: 'Paiement traité avec succès',
            responseType: 'ok'
        },
        abonnementNonTrouve: {
            description: 'L\'abonnement spécifié n\'existe pas',
            responseType: 'notFound'
        },
        abonnementDejaPaye: {
            description: 'L\'abonnement a déjà été payé',
            responseType: 'conflict'
        },
        montantIncorrect: {
            description: 'Le montant payé ne correspond pas au montant attendu',
            responseType: 'badRequest'
        },
        statutInvalide: {
            description: 'Le statut de l\'abonnement ne permet pas le paiement',
            responseType: 'badRequest'
        }
    },

    fn: async function (inputs, exits) {
        const { id, user } = this.req.token;
        // console.log("ID", id, user.login, user.typeUser, user.codeEcole)
        // VERIFICATION DU CODE ECOLE
        if (user.codeEcole === '' || user.codeEcole === null || user.codeEcole === undefined) {
            return exits.notFound({ message: "Veuillez préciser le code Ecole pour cet utulisateur pour a accéder a cette page!" })
        }
        ecoleVerif = await Ecoles.find({ codeEcole: user.codeEcole }).then(_.first)
        if (!ecoleVerif) {
            return exits.notFound({ message: "Cet utilisateur n'est attribué a aucune classe!" })
        }
        // FIN VERIF CODE ECOLE  
        try {
            // Vérifier que l'abonnement existe
            const abonnement = await Abonnement.findOne({ codeAbonnement: inputs.codeAbonnement, codeEcole: user.codeEcole });
            if (!abonnement) {
                return exits.abonnementNonTrouve({
                    message: 'Abonnement non trouvé',
                    code: 'SUBSCRIPTION_NOT_FOUND'
                });
            }

            // Vérifier que l'abonnement peut être payé
            if (abonnement.statut === 'actif' && abonnement.datePaiement) {
                return exits.abonnementDejaPaye({
                    message: 'L\'abonnement a déjà été payé',
                    code: 'SUBSCRIPTION_ALREADY_PAID'
                });
            }

            // Vérifier le statut
            if (!['en_attente_paiement', 'essai'].includes(abonnement.statut)) {
                return exits.statutInvalide({
                    message: `Le statut actuel (${abonnement.statut}) ne permet pas le paiement`,
                    code: 'INVALID_STATUS_FOR_PAYMENT'
                });
            }

            // Vérifier le montant
            const tolerance = 100; // Tolérance de 100 unités de devise
            if (Math.abs(inputs.montant - abonnement.montantFinal) > tolerance) {
                return exits.montantIncorrect({
                    message: `Le montant payé (${inputs.montant}) ne correspond pas au montant attendu (${abonnement.montantFinal})`,
                    code: 'INCORRECT_AMOUNT',
                    montantAttendu: abonnement.montantFinal,
                    montantPaye: inputs.montant
                });
            }

            // Créer la transaction
            const transaction = await TransactionAbonnement.create({
                abonnement: abonnement.id,
                codeEcole: user.codeEcole,
                codeAbonnement: inputs.codeAbonnement,
                codeParent: abonnement.codeParent,
                typeTransaction: 'paiement',
                statut: 'reussi',
                montant: inputs.montant,
                devise: inputs.devise,
                methodePaiement: inputs.methodePaiement,
                referencePaiement: inputs.referencePaiement,
                operateur: inputs.operateur,
                numeroTelephone: inputs.numeroTelephone,
                fraisTransaction: inputs.fraisTransaction,
                montantNet: inputs.montant - inputs.fraisTransaction,
                description: inputs.description || `Paiement pour abonnement ${abonnement.codeAbonnement}`,
                donneesTechniques: inputs.donneesTechniques,
                dateTransaction: new Date(),
                dateConfirmation: new Date()
            }).fetch();

            // Mettre à jour l'abonnement
            const now = new Date();
            // Recalcule dateDebut/dateFin à l'activation (durée basée sur l'offre)
            const offreActivation = await OffreAbonnement.findOne({ codeOffre: abonnement.codeOffre });
            let newDateDebut = abonnement.dateDebut;
            let newDateFin = abonnement.dateFin;
            if (offreActivation && now > new Date(abonnement.dateDebut)) {
                newDateDebut = now;
                const tmpFin = new Date(newDateDebut);
                tmpFin.setDate(tmpFin.getDate() + (offreActivation.dureeJours || 0));
                newDateFin = tmpFin;
            }
            const abonnementMisAJour = await Abonnement.updateOne({ codeAbonnement: inputs.codeAbonnement, codeEcole: user.codeEcole })
                .set({
                    statut: 'actif',
                    methodePaiement: inputs.methodePaiement,
                    referencePaiement: inputs.referencePaiement,
                    datePaiement: now,
                    dateDebut: newDateDebut,
                    dateFin: newDateFin
                });

            // Créer et envoyer une notification de paiement réussi
            const notification = await NotificationAbonnement.create({
                abonnement: abonnement.id,
                codeEcole: user.codeEcole,
                codeAbonnement: inputs.codeAbonnement,
                codeParent: abonnement.codeParent,
                typeNotification: 'paiement_reussi',
                titre: 'Paiement réussi',
                message: `Votre paiement de ${inputs.montant} ${inputs.devise} a été traité avec succès. Votre abonnement est maintenant actif.`,
                priorite: 'normale',
                statut: 'non_lue',
                dateEnvoi: new Date(), // Champ requis manquant
                canauxEnvoi: ['push', 'email', 'sms'], // Valeur par défaut
                statutEnvoi: { // Valeur par défaut
                    push: 'non_envoye',
                    email: 'non_envoye',
                    sms: 'non_envoye'
                }
            }).fetch();

            // Récupérer les informations du parent, utilisateur et de l'offre pour l'envoi
            const parent = await Parents.findOne({
                codeParent: abonnement.codeParent,
                codeEcole: user.codeEcole
            });
            const utilisateur = await Utilisateurs.findOne({
                codeUser: abonnement.codeParent,
                codeEcole: user.codeEcole
            });
            const offreInfo = await OffreAbonnement.findOne({
                codeOffre: abonnement.codeOffre,
                //codeEcole: user.codeEcole
            });

            // Envoyer la notification immédiatement
            if (offreInfo) {
                try {
                    await sails.helpers.sendAbonnementNotification.with({
                        notification: notification,
                        user: utilisateur,
                        parent: parent,
                        abonnement: abonnementMisAJour,
                        offre: offreInfo,
                        transaction: transaction
                    });
                } catch (notificationError) {
                    sails.log.error('Erreur lors de l\'envoi de la notification de paiement:', notificationError);
                }
            }

            // Récupérer les informations de l'offre pour la réponse
            const offre = await OffreAbonnement.findOne({ codeOffre: abonnement.codeOffre });

            return exits.success({
                message: 'Paiement traité avec succès',
                data: {
                    transaction: transaction,
                    abonnement: {
                        ...abonnementMisAJour,
                        offre: offre || null
                    }
                }
            });

        } catch (error) {
            sails.log.error('Erreur lors du traitement du paiement:', error);
            return exits.error({
                message: 'Erreur interne du serveur',
                error: error.message
            });
        }
    }
}; 