const db = require('../models');
const jwt = require('jsonwebtoken');
const { validationResult } = require('express-validator');
const authentification = require('../middlewares/authentification');
const bcrypt = require('bcrypt');
const Mail = require('../functions/mail');

const TokenModel = db.token;
var AdminModel = db.admin;

AdminModel.generateAuthTokenAndSave = async ( admin ) => {
    const Token = jwt.sign({ id: admin.id.toString() }, 'foo');
    let token = {
        authToken : Token,
        AdmnistratorId : admin.id
    };    
    let result = await TokenModel.create(token);
    return result;
}

const signupAdmin = async (req, res) => {
    const errors = validationResult(req);
    //  Erreur non vide
    if (!errors.isEmpty()) {       
        let admins = await db.admin.findAll({
            where: { role: 'Admin'}
        }); 
        return res.render('pages/log/signup', { admins ,errors: errors.array(), req })
    }
    //  Récupérer tout les données de l'admin
    let adminInformation = req.body; 
    
    //  Encadreur
    if( req.body.leader && req.body.leader !== 'superieur') {
        adminInformation.leader = req.body.leader;
    }
    else {
        adminInformation.leader = null;
    }
    
    //  Verifier que c'est un employee
    if(adminInformation && adminInformation.matriculeEmployee !== '') {
        let verify = await db.employee.findOne({ where:{ matricule: adminInformation.matriculeEmployee }})        
        if(!verify) {
            let err = [{
                msg: "Employé(e) non inscrit."
            }]
            let admins = await db.admin.findAll({
                where: { role: 'Admin'}
            });         
            return res.render('pages/log/signup', { admins ,errors: err, req });
        }
    }

    //  Verifier que le matricule est pas encore utiliser   
    if(adminInformation.matriculeEmployee !== '') {

        let verifyMatricule = await db.admin.findOne({ where:{ matriculeEmployee: adminInformation.matriculeEmployee}})
        if( verifyMatricule ) {
            let err = [{
                msg: "Matricule utilisé par autre compte"
            }]
            let admins = await db.admin.findAll({
                where: { role: 'Admin'}
            });         
            console.log(verifyMatricule);
            return res.render('pages/log/signup', { admins ,errors: err, req });
        }    
    }
    else {
        adminInformation.matriculeEmployee = null;
    }

    let admin = await AdminModel.findOne({
        where: { email: adminInformation.email }
    });    

    //  Vérifier si l'email est déjà utilisé
    if(admin) {
        let err = [{
            msg: "Adresse E-mail existant"
        }]
        let admins = await db.admin.findAll({
            where: { role: 'Admin'}
        });
        return res.render('pages/log/signup', { admins ,errors: err, req });
    }

    //  Générer un sel pour le hachage
    const saltRounds = Number(process.env.SALTROUNDS);
    console.log(saltRounds)
    const salt = bcrypt.genSaltSync(saltRounds);

    //  Mots de passe par defaut
    adminInformation.password = process.env.PASSWORD_TEMPO;

    // Crypter le mot de passe
    adminInformation.password = bcrypt.hashSync(
            adminInformation.password,
            salt
        );

    // Enregistrer l'admin
    let adminSaved = await AdminModel.create(adminInformation);    
    
    res.redirect(`/admin/${adminSaved.id}`);    
}

const signinAdmin = async (req, res ) => {
    try {
        let adminInfo = req.body;
        
        let admin = await AdminModel.findOne({
            where: {
                email: adminInfo.email,                         
            }
        });  
        
        // Vérifier le mot de passe
        const isMatch = bcrypt.compareSync(adminInfo.password, admin.password);     
        //return res.send('v' + admin + isMatch);
        if( admin && isMatch ) {
            const authToken = await AdminModel.generateAuthTokenAndSave(admin);                        

            //  Si l'admin utilise le mdp temporaire, guider a le modifié
            if(adminInfo.password == process.env.PASSWORD_TEMPO){                                                                                                
                return res.redirect(`reset-password/${authToken.authToken}`);
            }
            req.session.token = authToken.dataValues.authToken;
            req.session.admin = admin;            
            authentification;
            res.redirect('/');
        }  
        else {
            let errors = [{
                msg: "E-mail ou mot de passe incorrect"
            }];
            res.render('pages/log/signin', { errors, req })
        }      
    }catch(err) {
        console.log(err)
        let errors = [{
            msg: "E-mail ou Mot de passe incorrect"
        }];
        res.render('pages/log/signin', { errors, req })
    }
}

const logoutAdmin = async (req, res) => {
    try {

        //  Effacer le token dans la base de donnees
        if(req.session.token !== null){
            await TokenModel.destroy({
                where: {
                    authToken: req.session.token
                }
            })
        }
        console.log(req.session.cookie)
        req.session.destroy();        
        res.redirect('/admin/signin')

    } catch(err) {
        console.log(err);
        res.status(500).send();
    }
}


const resetPassWord = async (req, res) => {    
    const { email } = req.body;

    // Vérification de l'e-mail dans la base de données
    const admin = await AdminModel.findOne({ where: { email: email }});    
    if (!admin) {
        let errors = [{
            msg: "Utilisateur introuvable"
        }];
        let message;
        res.render('pages/log/reset_mdp_mail', {errors: errors, message, req })
    }
    else {

        // Générer un token de réinitialisation de mot de passe (vous pouvez utiliser des bibliothèques comme `crypto` pour cela)
        // Enregistrer le token de réinitialisation de mot de passe dans la base de données        
        const resetToken = await AdminModel.generateAuthTokenAndSave(admin);
        const DELAY = 15 * 60 * 1000;   //  15 minutes

        //  Expriree le token apres 15 mn si l'utilisateur ne modifie pas leur mot de passe
        setTimeout(async () => {
            let token = await db.token.findOne({
                where : { authToken : resetToken.authToken }
            });
            if (token) {
                await token.destroy();
                console.log('Token expiree')
            }
        }, DELAY)
    
        // Envoyer l'e-mail de réinitialisation de mot de passe avec le lien contenant le token
        const site = process.env.ENV == 'prod' ? process.env.SITE : process.env.LOCAL + ':' + process.env.PORT;
        const resetLink = `http://${site}/admin/reset-password/${resetToken.authToken}`;        
        const emailDetails = {            
            recipient: email,
            subject: 'Réinitialisation de mot de passe',
            message: `Cliquez sur le lien suivant pour réinitialiser votre mot de passe : ${resetLink}`,
        };        
        let response = Mail.sendEmail(emailDetails);
        if (response) {            
            let message = 'E-mail de réinitialisation de mot de passe envoyé';
            let errors;
            res.render('pages/log/reset_mdp_mail', {errors: errors, message, req });    
        }
    }
}


const update = async (req, res) => {
    const errors = validationResult(req);
    //  Erreur non vide
    if (!errors.isEmpty()) {         
        let admin = await db.admin.findOne({ where: { id: req.body.id } });
        let leaders = await db.admin.findAll({
            where: { role: 'Admin'}
        });
        return res.render('pages/log/signup.edit.ejs', { leaders ,admin, errors, req })               
    } 
    //  Récupérer tout les données de l'admin
    let adminInformation = req.body;      
    
    //  Encadreur
    if( req.body.leader && req.body.leader !== 'superieur') {
        adminInformation.leader = req.body.leader;
    }
    else {
        adminInformation.leader = null;
    }

    //  Verifier que c'est un employee
    let verify = await db.employee.findOne({ where:{ matricule: adminInformation.matriculeEmployee }})        
    if(!verify) {
        let err = [{
            msg: "Employé(e) non inscrit."
        }]
        let admin = await db.admin.findOne({ where: { id: req.body.id } });
        let leaders = await db.admin.findAll({
            where: { role: 'Admin'}
        });
        console.log('ttttttttsssssssssssssssssssssssssss');
        // return res.render('pages/log/signup.edit.ejs', { leaders ,admin, errors, req })            
    }

    let newAdmin = await AdminModel.findOne({
        where: { email: adminInformation.email }
    });

    let oldAdmin = await AdminModel.findOne({
        where: { id: req.body.id }
    });

    //  l'admin change le mail et vérifier si l'email est déjà utilisé
    if(newAdmin && newAdmin.email !== oldAdmin.email ) {
        let err = [{
            msg: "Adresse E-mail existant"
        }]
        let leaders = await db.admin.findAll({
            where: { role: 'Admin'}
        });
        return res.render('pages/log/signup.edit.ejs', { leaders ,admin, errors, req })              
    }    
    
    await AdminModel.update(adminInformation,{ where:{ id: req.body.id }});
    let adminSaved = await AdminModel.findOne({
        where: { id: req.body.id }
    });
        
    res.redirect(`/admin/${req.body.id}`);
    
}



module.exports = {
    signupAdmin,
    signinAdmin,
    logoutAdmin,
    resetPassWord,
    update
}