const fs = require('fs')
const SamlStrategy = require('passport-saml').Strategy
const dbconn = require('./dbconn')
const methods = require('./methods')
// pwd encryption
const bcrypt = require('bcryptjs');
const saltRounds = 10;
const salt = 64; // salt length
// forgot pwd
const async = require('async')
const crypto = require('crypto')
const mailer = require('./mailer')

module.exports = function (app, config, passport, i18n) {

  // =========== PASSPORT =======
  passport.serializeUser(function (user, done) {
    done(null, user);
  });

  passport.deserializeUser(function (user, done) {
    done(null, user);
  });

  var samlStrategy = new SamlStrategy({
      // URL that goes from the Identity Provider -> Service Provider
      callbackUrl: config.passport.saml.path,
      // Base address to call logout requests
      logoutUrl: config.passport.saml.logoutUrl,
      
      entryPoint: config.passport.saml.entryPoint,
      issuer: config.passport.saml.issuer,
      identifierFormat: null,
      
      // Service Provider private key
      decryptionPvk: fs.readFileSync(__dirname + '/cert/key.pem', 'utf8'),
      // Service Provider Certificate
      privateCert: fs.readFileSync(__dirname + '/cert/key.pem', 'utf8'),
      // Identity Provider's public key
      cert: fs.readFileSync(__dirname + '/cert/cert_idp.pem', 'utf8'),
      
      validateInResponseTo: false,
      disableRequestedAuthnContext: true
  },
  function (profile, done) {
    return done(null, {
      id: profile.nameID,
      idFormat: profile.nameIDFormat,
      email: profile.email,
      firstName: profile.givenName,
      lastName: profile.sn
    });
  });
  
  passport.use(samlStrategy);

  // ============= SAML ==============
  app.post(config.passport.saml.path,
    passport.authenticate(config.passport.strategy,
      {
        failureRedirect: '/account/',
        failureFlash: true
      }),
    function (req, res) {
      res.redirect('/account/');
    }
  );

  // to generate Service Provider's XML metadata
  app.get('/saml/metadata',
    function(req, res) {
      res.type('application/xml');
      var spMetadata = samlStrategy.generateServiceProviderMetadata(fs.readFileSync(__dirname + '/cert/cert.pem', 'utf8'));
      res.status(200).send(spMetadata);
    }
  );

  // ================ test i18n ==================
  i18n.setLocale('de');
  app.get('/de', function(req, res) {
    var greeting = i18n.__('Hello World')
    res.send(greeting)
  });

  var lang = 'DE'

  // ======== APP ROUTES - ACCOUNT ====================
  var updatePasswordMailSubject = "Ihr Passwort für das Transferportal wurde gespeichert."
  var mailSignature = "Mit den besten Grüßen,\ndas Transferportal-Team der HFT Stuttgart\n\n"+
    "Transferportal der Hochschule für Technik Stuttgart\n"+
    "Schellingstr. 24\n"+
    "70174 Stuttgart\n"+
    "m4lab@hft-stuttgart.de\n"+
    "https://transfer.hft-stuttgart.de"
  var updatePasswordMailContent = "Lieber Nutzer,\n\n"+"Ihr Passwort wurde erfolgreich geändert.\n\n"+mailSignature

  app.get('/', function (req, res) {
    if (req.isAuthenticated()) {
      methods.getUserByEmail(req.user.email, function(data, err){
        if (!err) {
          res.render(lang+'/account/home', {
            user: data
          });
        }
      })
    } else {
      res.redirect('/login'); // localhost
    }
  });

  app.get('/login',
    passport.authenticate(config.passport.strategy,
      {
        successRedirect: '/',
        failureRedirect: '/login'
      })
  );

  app.get('/logout', function (req, res) {
    if (req.user == null) {
      return res.redirect('/');
    }

    req.user.nameID = req.user.id;
    req.user.nameIDFormat = req.user.idFormat;
    return samlStrategy.logout(req, function(err, uri) {
      req.logout();

      if ( req.session ) {
        req.session.destroy((err) => {
          if(err) {
              return console.log(err);
          }
        });
      }

      return res.redirect(uri);
    });
  });

  app.get('/profile', function (req, res) {
    if (req.isAuthenticated()) {
      methods.getUserByEmail(req.user.email, function(data, err){
        if (!err) {
          res.render(lang+'/account/profile', {
            user: data,
            email: req.user.email
          });
        }
      })
    } else {
      res.redirect('/login');
    }
  });

  app.get('/services', function (req, res) {
    if (req.isAuthenticated()) {
      async.waterfall([
        // get userId by email from userdb
        function(done) {
          methods.getUserIdByEmail(req.user.email, function(userId, err) {
            if (!err) {
              done(err, userId)
            }
          })
        },
        // get user-project-role from userdb
        function(userId, done) {
          methods.getUserProjectRole(userId, function(userProjects, err) {
            if (!err) {
              done(err, userProjects)
            }
          })
        },
        // get all projects from projectdb
        function(userProjects, done) {
          methods.getAllProjects(function(projectsOverview, err) {
            if (!err) {
              done(err, userProjects, projectsOverview)
            }
          })
        },
        // create JSON object of projects and user status for front-end
        function(userProjects, projectsOverview, done) {
          var allProjects = []  // JSON object

          var userProjectId = []  // array of user's project_id
          for (var i = 0; i < userProjects.length; i++) {
            userProjectId.push(userProjects[i].project_id)
          }

          for (var i = 0; i < projectsOverview.length; i++) {
            // check if projectId is exist in userProjectId[]
            var status = false
            if (userProjectId.indexOf(projectsOverview[i].id) > -1) {
              status = true
            }
            // add data to JSON object
            allProjects.push({
              id: projectsOverview[i].id,
              title: projectsOverview[i].title,
              summary: projectsOverview[i].onelinesummary,
              cp: projectsOverview[i].contact_email,
              userStatus: status
            });
          }

          // render the page
          res.render(lang+'/account/services', {
            user: req.user,
            project: allProjects
          });
        }
      ])
    } else {
      res.redirect('/login');
    }
  });

  app.get('/security', function (req, res) {
    if (req.isAuthenticated()) {
      res.render(lang+'/account/security', {
        user: req.user // useful for view engine, useless for HTML
      });
    } else {
      res.redirect('/login');
    }
  });

  app.post('/updateProfile', function (req, res) {
    var userData = {
      salutation: req.body.inputSalutation,
      title: req.body.inputTitle,
      firstname: req.body.inputFirstname,
      lastname: req.body.inputLastname,
      email: req.body.inputEmail,
      organisation: req.body.inputOrganisation,
      industry: req.body.inputIndustry,
      speciality: req.body.inputSpeciality,
    }

    if (req.isAuthenticated()) {
      if (userData.email) {
        dbconn.user.query('UPDATE user SET ? WHERE email = "' +userData.email+'"', userData, function (err, rows, fields) {
            //if (err) throw err;
            if (err) {
              req.flash('error', "Failed");
            }
            else {
              //req.flash('success', 'Profile updated!');
              req.flash('success', 'Ihr Benutzerprofil wurde aktualisiert!');
            }
            res.redirect('/account/profile');
        })
      }
    } else {
      res.redirect('/login');
    }
  });

  app.post('/changePwd', function (req, res) {
    if (req.isAuthenticated()) {
      var currPwd = req.body.inputCurrPwd
      var newPwd = req.body.inputNewPwd
      var retypePwd = req.body.inputConfirm

      methods.getUserIdByEmail(req.user.email, function(userId, err) {
        if (!err) {
          // Load hashed passwd from DB
          dbconn.user.query('SELECT password FROM credential WHERE user_id='+userId, function (err, rows, fields) {
            if (err) {
              console.error(err)
              res.status(500).render(lang+'/500', {
                error: err
              })
            }
            var userPwd = rows[0].password

            // check if the password is correct
            bcrypt.compare(currPwd, userPwd, function(err, isMatch) {
              if (err) {
                console.error(err)
                res.status(500).render(lang+'/500', {
                  error: err
                })
              }
              else if (!isMatch) {
                //req.flash('error', "Sorry, your password was incorrect. Please double-check your password.")
                req.flash('error', "Das Passwort ist leider falsch. Bitte überprüfen Sie Ihre Eingabe.")
                //res.redirect('/security')
                res.redirect('/account/security')
              }
              else {
                if ( newPwd != retypePwd ) {
                  //req.flash('error', "Passwords do no match. Please make sure you re-type your new password correctly.")
                  req.flash('error', 'Passwörter stimmen nicht überein. Bitte stellen Sie sicher, dass Sie das Passwort beide Male genau gleich eingeben.')
                  res.redirect('/account/security')
                }
                else {
                  // update password
                  bcrypt.genSalt(saltRounds, function(err, salt) {
                    bcrypt.hash(newPwd, salt, function(err, hash) {
                      var credentialData = {
                        password: hash,
                        user_id: userId
                      }
                      methods.updateCredential(credentialData, function(err){
                        if (err) {
                          //req.flash('error', "Database error: Password cannot be modified.")
                          req.flash('error', "Datenbankfehler: Passwort kann nicht geändert werden.")
                          throw err
                        }
                        else {
                          //req.flash('success', "Pasword updated!")
                          req.flash('success', "Passwort aktualisiert!")
                          mailer.options.to = req.user.email
                          //mailOptions.subject = "Your M4_LAB Password has been updated."
                          mailer.options.subject = updatePasswordMailSubject
                          mailer.options.text = updatePasswordMailContent
                          mailer.transport.sendMail(mailer.options, function(err) {
                            if (err) {
                              console.log(err)
                            }
                          });
                        }
                        res.redirect('/account/security')
                      })
                    });
                  });
                }
              }
          })
        })
        }
      })
    }
    else {
      res.redirect('/login');
    }
  });

  app.get('/forgotPwd', function (req, res) {
    res.render(lang+'/account/forgotPwd', {
      user: req.user
    });
  });

  app.post('/forgotPwd', function(req, res, next) {
    //methods.currentDate();

    var emailAddress = req.body.inputEmail;
  /*  var emailContent = "Hi there,\n\n"+
      "we've received a request to reset your password. However, this email address is not on our database of registered users.\n\n"+
      "Thanks,\nM4_LAB Team";
    var emailSubject = "Account Access Attempted"; */

    async.waterfall([
      function(done) {
        crypto.randomBytes(20, function(err, buf) {
          var token = buf.toString('hex');
          done(err, token);
        });
      },
      function(token, done) {
        methods.checkUserEmail(emailAddress, function(err, user){
          if (user) {
            console.log("email: user found");
            //var emailSubject = "M4_LAB Password Reset";
            var emailSubject = "Ihre Passwort-Anfrage an das Transferportal der HFT Stuttgart";
            /* var emailContent = "Hi User,\n\n"+
              "we've received a request to reset your password. If you didn't make the request, just ignore this email.\n\n"+
              "Otherwise, you can reset your password using this link: http://m4lab.hft-stuttgart.de/account/reset/" + token + "\n" +
              "This password reset is only valid for 1 hour.\n\n"+
              "Thanks,\nM4_LAB Team" */
            var emailContent = "Lieber Nutzer,\n\n"+
              "wir haben Ihre Anfrage zur Erneuerung Ihres Passwortes erhalten. Falls Sie diese Anfrage nicht gesendet haben, ignorieren Sie bitte diese E-Mail.\n\n"+
              "Sie können Ihr Passwort mit dem Klick auf diesen Link ändern: http://m4lab.hft-stuttgart.de/account/reset/" + token + "\n" + // test server
              //"Sie können Ihr Passwort mit dem Klick auf diesen Link ändern: http://localhost:9989/reset/" + token + "\n" + // localhost
              "Dieser Link ist aus Sicherheitsgründen nur für 1 Stunde gültig.\n\n"+mailSignature

            var credentialData = {
              user_id: user.id,
              resetPasswordToken: token,
              resetPasswordExpires: Date.now() + 3600000 // 1 hour
            }
            methods.updateCredential(credentialData, function(err) {
              done(err, token, user);
            });

            // send email
            mailer.options.to = emailAddress;
            mailer.options.subject = emailSubject;
            mailer.options.text = emailContent;
            mailer.transport.sendMail(mailer.options, function(err) {
              done(err, 'done');
            });
          }
          else {
            //done(err, null, null);
            done(err, 'no user found');
          }
        });
      }
    ], function(err) {
      if (err) {
        //req.flash('error', 'An error occured. Please try again.');
        req.flash('error', 'Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut.');
      }
      else {
        //req.flash('success', 'If your email is registered, an e-mail has been sent to ' + emailAddress + ' with further instructions.');
        req.flash('success', 'Wenn Ihre E-Mail-Adresse registriert ist, wurde eine E-Mail mit dem weiteren Vorgehen an ' + emailAddress + ' versendet.');
      }
      //res.redirect('/forgotPwd'); // deployment
      res.redirect('/account/forgotPwd'); // localhost
    });
  });

  app.get('/reset/:token', function(req, res) {
    methods.getUserByToken(req.params.token, function(err, user){
      if (!user) {
        //req.flash('error', 'Password reset token is invalid or has expired.');
        req.flash('error', 'Der Schlüssel zum zurücksetzen des Passworts ist ungültig oder abgelaufen.');
        //res.redirect('/forgotPwd'); // deployment
        res.redirect('/account/forgotPwd'); // deployment
      }
      else {
        res.render(lang+'/account/reset');
      }
    });
  });

  app.post('/reset/:token', function(req, res) {
    var newPwd = req.body.inputNewPwd
    methods.getUserByToken(req.params.token, function(err, user){
      if (user) {
        // encrypt password
        bcrypt.genSalt(saltRounds, function(err, salt) {
          bcrypt.hash(newPwd, salt, function(err, hash) {
            var credentialData = {
              password: hash,
              user_id: user.user_id
            }
            // update password
            methods.updateCredential(credentialData, function(err){
              if (err) {
                //req.flash('error', "Database error: Password cannot be modified.")
                req.flash('error', "Datenbankfehler: Passwort kann nicht geändert werden.")
                throw err
              }
              else {
                //req.flash('success', "Your pasword has been updated.")
                req.flash('success', "Passwort aktualisiert!")
                // send notifiaction email
                mailer.options.to = user.email
                mailer.options.subject = updatePasswordMailSubject
                mailer.options.text = updatePasswordMailContent
                mailer.transport.sendMail(mailer.options, function(err) {
                  if (err) {
                    console.log(err)
                  }
                });
                // redirect to login page
                res.redirect('/login')
              }
            })
          });
        });
      }
      else {
        req.flash('error', "User not found.")
        res.redirect('/login')
      }
    });

  });

  // todo: user registration with captcha
  app.get('/registration', function(req, res) {
    res.render(lang+'/account/registration')
  })

  app.post('/registration', function(req, res) {
    // TODO:
    // create gitlab account?
    // send email to activate profile?

    // user data
    var curDate = new Date()
    var userData = {
      salutation: req.body.inputSalutation,
      title: req.body.inputTitle,
      firstname: req.body.inputFirstname,
      lastname: req.body.inputLastname,
      email: req.body.inputEmail,
      organisation: req.body.inputOrganisation,
      industry: req.body.inputIndustry,
      speciality: req.body.inputSpeciality,
      createdDate: curDate.toISOString().slice(0,10)
    }
    // encrypt password
    bcrypt.genSalt(saltRounds, function(err, salt) {
      bcrypt.hash(req.body.inputPassword, salt, function(err, hash) {
        // create account
        var newAccount = {
          profile: userData,
          password: hash
        }
        methods.registerNewUser(newAccount, function(err){
          if (err) {
            //req.flash('error', "Failed")
            req.flash('error', "Fehlgeschlagen")
          }
          else {
            //req.flash('success', 'Your account has been created. Please log in.')
            req.flash('success', 'Ihr Benutzerkonto wurde angelegt. Bitte melden Sie sich an.')
          }
          res.redirect('/account/registration');
        })
      });
    });
  })

  app.get('/email/:email', function(req, res) {
    methods.checkUserEmail(req.params.email, function(err, user){
      if (!err) {
        if (user) {
          res.send(false)
        }
        else {
          res.send(true)
        }  
      }
    })
  })

  app.get('/contact', function (req, res) {
      res.render(lang+'/account/contact', {
        user: req.user
      });
    });

    app.post('/contact', function(req, res, next) {
      //methods.currentDate();
      let emailAddress = req.body.inputEmail;
      let supportAddress = "support-transfer@hft-stuttgart.de";
      let inputName = req.body.name;
      let inputContent = req.body.message;
      let emailContent = "Es wurde eine Anfrage an das Transferportal gestellt: \n\n NAME: " + inputName + "\n NACHRICHT:\n "+ inputContent;
      let emailSubject = "Ihre Anfrage an das Transferportal";
      async.waterfall([
        function(done) {
            // send email
            mailer.options.to = supportAddress;
            mailer.options.cc = emailAddress;
            mailer.options.subject = emailSubject;
            mailer.options.text = emailContent;
            mailer.transport.sendMail(mailer.options, function(err) {
                done(err, 'done');
              });
          }
      ], function(err) {
        if (err) {
          req.flash('error', 'Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut.');
        }
        else {
          req.flash('success', 'Vielen Dank für Ihre Anfrage. Wir melden uns baldmöglichst bei Ihnen. Eine Kopie Ihrer Anfrage wurde an ' + emailAddress + ' versandt.');
        }
        //res.redirect('/forgotPwd'); // deployment
        res.redirect('/account/contact'); // localhost
      });
    });
};