const express = require('express')
const mysql = require("mysql2")
const dotenv = require('dotenv')
const app = express()
const path = require("path")
const publicDir = path.join(__dirname, './public')
const bodyParser = require('body-parser')
const functions = require(publicDir + "/functions");
const bcrypt = require("bcrypt")
const saltRounds = 10;


/* Connexion à la BDD MySQL */
dotenv.config({ path: './.env'})
const db = mysql.createConnection({
    host: process.env.DATABASE_HOST,
    port: process.env.DATABASE_PORT,
    user: process.env.DATABASE_USER,
    password: process.env.DATABASE_PASSWORD,
    database: process.env.DATABASE
})
db.connect((error) => {
    if(error) {
        console.log(error)
    } else {
        console.log("MySQL connected!")
    }
})

app.set('view engine', 'hbs');
app.use(express.static(publicDir));
app.use('/css', express.static(__dirname + '/node_modules/bootstrap/dist/css'));
app.use('/css', express.static(__dirname + '/node_modules/@eonasdan/tempus-dominus/dist/css'));
app.use('/js', express.static(__dirname + '/node_modules/@eonasdan/tempus-dominus/dist/js'));
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());


// *******************************************    Arrivée sur la page d'accueil    *******************************************
app.get("/", (req, res) => { 
    let today = functions.getNowDate("yyyymmdd");

    // On récupère la liste des sessions actives et pour lesquelles il reste de la place
    db.query('SELECT ID, topic, DATE_FORMAT(scheduled_on, "%d/%m/%Y") as "date", DATE_FORMAT(scheduled_on, "%Hh%i") as "heure", IF(nb_of_attended-nb_of_participants=0, true, false) as "maxAtteint" FROM session WHERE DATE_FORMAT(scheduled_on, "%Y%m%d") >= ?', [today], async (error, result) => {
        if(error){ console.log(error); }
        if (result && result.length == 0) {
            res.render("login-session", { error: 'Aucune session disponible' });
        }
        else {
            res.render("login-session", { select: result} );
        }
    });
 });

app.get("/index", (req, res) => { res.render("index") });
app.get("/login", (req, res) => { res.render("login") });
app.get("/register", (req, res) => { res.render("register", { session: req.query.s, role: req.query.r}) });
app.get("/create-session", (req, res) => { res.render("create-session") });



// *******************************************   Création d'un nouveau compte   *******************************************
app.post("/auth/register", (req, res) => {    
    const { gender, name, firstname, nickname, title, email, password, password_confirm, session, role } = req.body

    let requete = '';
    if (nickname != '') {
        requete = "SELECT * FROM user WHERE UPPER(nickname) = '?'".replace("?", nickname.toUpperCase());
    }
    if (email != '') {
        requete = "SELECT * FROM user WHERE UPPER(email) = '?'".replace("?", email.toUpperCase());
    }

    if (requete.length > 0) {
        let topic, sessionDate;

        db.query(requete, async (error, result) => {
            if(error){
                console.log(error)
            }
            if( result.length > 0 ) {
                return res.render('register', {
                    error: 'Adresse email ou pseudo déjà utilisé : modifiez votre saisie ou bien cliquez sur le lien ci-dessus pour vous connecter',
                    session: session, role: role
                })
            } else if(password !== password_confirm) {
                return res.render('register', { 
                    error: 'Vos mots de passe ne correspondent pas',
                    session: session, role: role
                })
            }

            db.query('SELECT topic, DATE_FORMAT(scheduled_on, "%d/%m/%Y %H:%i") as "date" FROM session WHERE id = ?', [session], (err, result) => {
                if(error){
                    console.log(error)
                }
                if( result.length > 0 ) {
                    topic = result[0].topic;
                    sessionDate = result[0].date;
                }
            })

            bcrypt.genSalt(saltRounds, (err, salt) => {
                bcrypt.hash(password, salt, (err, hash) => {
                    db.query('INSERT INTO user SET?', {gender : (gender != undefined ? gender : ""), firstname: firstname, name: name, title: title, email: email, nickname : nickname, password: hash}, (err, result) => {
                        if(error) {
                            console.log(error)
                        } else {
                            return res.render('login', { session: session, role: role, email: email, nickname: nickname, topic: topic, session_date: sessionDate })
                        }
                    }) 
                })
            })
        })
    }
})




// *******************************************    Connexion sur le compte utilisateur  (sans sécurité)  *******************************************
app.post("/auth/check-login-no-security", (req, res) => {
    let newUser;
    const { nickname, role, session } = req.body;

    db.query('SELECT ID FROM user WHERE UPPER(nickname)=? AND session=?', [nickname.toUpperCase(), session], (error, result) => {
        if(error){ console.log(error) }
        if(result && result.length > 0) {
            return res.render('login', {
                error: 'Identifiant déjà utilisé : veuillez en choisir un autre',
                session: session,
                role: role
            });
        }
        else {
            // On crée l'utilisateur pour traçabilité
            var newUser = functions.getUuid();
            db.query('INSERT INTO user SET?', {id: newUser, nickname : nickname, session: session}, (error, result) => {
                if(error){ console.log(error); rollback(session, newUser); }
                if(result && result.affectedRows > 0) {
                    // On trace la connexion de l'utilisateur à la session...
                    db.query('INSERT INTO participation (user, session, role_during_session) VALUES (?,?,?)', [newUser, session, role], function (error, result) {
                        if(error){ console.log(error); rollback(session, newUser);}
                        if(result.affectedRows > 0) {
                            console.log("1 record inserted");
                        }
                    });

                    // ... et on incrémente le nb de participants.
                    db.query('UPDATE session SET nb_of_participants = nb_of_participants + 1 WHERE ID=?', [session], function (error, result) {
                        if (error) { console.log(error); rollback(session, newUser); }
                        console.log("1 record updated");
                    });            
                }

                if (role == 'A') { res.redirect(process.env.MASTER_URL); }
                else { res.redirect(process.env.SLAVE_URL); }
            });
        }
    });
});


// *******************************************    Connexion sur le compte utilisateur  (mode sécurisé)  *******************************************
app.post("/auth/check-login", (req, res) => {
    var userId, 
        passwordStocke; 
    const { email, nickname, password, role, session } = req.body

    if (email == '' && nickname == '') {
        return res.render('login', {
            error: 'Veuillez saisir soit votre pseudo, soit une adresse email',
            session: session, role: role
        })
    }

    let requete = '';
    if (nickname != '') {
        requete = "SELECT * FROM user WHERE UPPER(nickname) = '?'".replace("?", nickname.toUpperCase());
    }
    if (email != '') {
        requete = "SELECT * FROM user WHERE UPPER(email) = '?'".replace("?", email.toUpperCase());
    }
    db.query(requete, async (error, result) => {
        if(error){
            console.log(error)
        }

        if( result.length == 0 ) {
            return res.render('login', {
                error: 'Utilisateur inconnu : veuillez créer votre compte via le lien ci-dessus',
                session: session,
                role: role
            })
        }

        userId = result[0].ID;

        bcrypt.compare(password, result[0].password)
        .then(result => {
            if (result) {
                if (result.length == 0) {
                    db.query('INSERT INTO participation (user, session, role_during_session) VALUES (?,?,?)', [userId, session[0], role[0]], function (err, result) {
                        if (err) throw err;
                        console.log("1 record inserted");
                        });

                    db.query('UPDATE session SET nb_of_participants = nb_of_participants + 1 WHERE ID=?', session, function (err, result) {
                        if (err) throw err;
                        console.log("1 record updated");
                        });
                }

                if (role == 'A') { res.redirect('https://slave.thecoredev.fr'); }
                else { res.redirect('https://slave.thecoredev.fr'); }
            }
            else {
                return res.render('login', {
                    error: 'Mot de passe incorrect : corriger votre saisie',
                    session: session,
                    role: role
                })
            }
        })
    })
})


// *******************************************    Connexion sur la session    *******************************************
app.post("/auth/check-session", (req, res) => { 
    
    const { session, session_password, role } = req.body
    let listeSessions;    
    let today = functions.getNowDate("yyyymmdd");

    db.query('SELECT ID, topic, DATE_FORMAT(scheduled_on, "%d/%m/%Y") as "date", DATE_FORMAT(scheduled_on, "%Hh%i") as "heure", IF(nb_of_attended-nb_of_participants=0, true, false) as "maxAtteint" FROM session WHERE DATE_FORMAT(scheduled_on, "%Y%m%d") >= ?', [today], async (error, result) => {
        if(error){ console.log(error); }
        if (result.length == 0) {
            res.redirect('');
        }
        else {
            listeSessions = result;
        }
    });

    db.query('SELECT password, topic, DATE_FORMAT(scheduled_on, "%d/%m/%Y %H:%i") as "date" FROM session WHERE ID = ?', [session], async (error, result) => {
        if(error){
            console.log(error)
        }
        if( result.length == 0 ) {
            return res.render('login-session', {
                error: 'Session inconnue : veuillez saisir un identifiant de session valide'
            })
        }
        else {
            let sessionDate = result[0].date;
            let sessionTopic = result[0].topic;
            bcrypt.compare(session_password, result[0].password)
                .then(result => {
                    if (result) {  return res.render('login', {"session": session, "role": role, "topic": sessionTopic, "session_date": sessionDate}) }
                    else {
                        return res.render('login-session', {
                            "error": "Mot de passe incorrect : corriger votre saisie",
                            "select": listeSessions
                        })
                    }
                })
                .catch(err => {
                    console.log(err);
                })
          }
    })
})


// *******************************************    Création d'une nouvelle session  *******************************************
app.post("/record-session", async (req, res) => {    
    const { topic, attended, password, password_confirm, datetimepicker1Input } = req.body

    // On traite d'abord les motifs de rejet du formulaire.
    if (isNaN(attended) || (!isNaN(attended) && attended < 0)) {
        return res.render('create-session', {
            error: "Le nombre de participants n'a pas une valeur correcte."
        })
    }
    if(password !== password_confirm) {
        return res.render('create-session', { 
            error: 'Vos mots de passe ne correspondent pas'
        })
    }

    var newSessionId = functions.getUuid();

    bcrypt.genSalt(saltRounds, (err, salt) => {
        bcrypt.hash(password, salt, (err, hash) => {
            db.query("INSERT INTO session (id, topic, password, nb_of_attended, scheduled_on) VALUES (?,?,?,?,STR_TO_DATE(?,'%d/%m/%Y %H:%i'))", [newSessionId, topic, hash, attended, datetimepicker1Input], (error, result) => {
                if(error){ console.log(error); }
                if(result && result.affectedRows > 0) {
                    res.redirect('/');
                }
            });
        });
    });
});


app.listen(5005, ()=> {
    console.log("server started on port 5005")
})