const passport = require('passport');
const localStrategy = require('passport-local').Strategy;
const JWTstrategy = require('passport-jwt').Strategy;
const ExtractJWT = require('passport-jwt').ExtractJwt;
const User = require('../src/models/user');

// Passport middleware for registering new users, creates the user and fowards the request to registration controller.
passport.use(
    'signup',
    new localStrategy(
      {
        usernameField: 'email',
        passwordField: 'password',
        passReqToCallback: true
      },
      async (req,email, password, done) => {
        try {
          findOrCreateUser = function(){
            // set the user's local credentials
            const {name,tel,roles,rfc} = req.body;

            // Generate username using name
            let nameArr = name.split(" ");

            let username = nameArr[0].replace(/[^a-zA-Z ]/g, "");

            if(username.length < 3 && nameArr.length > 1) username += nameArr[1].replace(/[^a-zA-Z ]/g, "");

            // find a user in Mongo with provided username
            User.find({email: email, 'username':new RegExp(username, 'i')},function(err, user) {
              // In case of any error return
              if (err){
                console.log('Error in Signup: ' + err);
                return done(err);
              }
              // already exists
              if (user.length) {
                // adding number if user already exist with same email and username
                username += user.length;
              }

                // if there is no user with that email
                // create the user
                let newUser = new User();

                newUser.name = name ? name : "";
                newUser.username = username;
                newUser.email = email;
                newUser.password = password;
                newUser.roles = roles ? roles : "client";
                newUser.rfc = rfc;
                newUser.tel = tel ? tel : "";
                newUser.referenceToken = Math.floor(1000 + Math.random() * 9000);

                // save the user
                newUser.save(function(err) {
                  if (err){
                    console.log('Error in Saving user: '+err);
                    throw err;
                  }
                  console.log('User Registration succesful');
                  return done(null, newUser);
                });
            });
          };
          // Delay the execution of findOrCreateUser and execute
          // the method in the next tick of the event loop
          process.nextTick(findOrCreateUser);

        } catch (error) {
          done(error);
        }
      }
    )
);

// Passport middleware for loggin in user, it gets the token for the user.
passport.use(
    'login',
    new localStrategy(
        {
        usernameField: 'email',
        passwordField: 'password',
        passReqToCallback: true,
        },
        async (req,email, password, done) => {
        try {
            const { username } = req.body;
            let usernameLower = username.toLowerCase();
            const user = await User.findOne({ email: email, username: usernameLower});

            if (!user || !user.isValid) {
            req.res.status(401);
            return req.res.send({error: 'User not found' });
            }

            if (user.roles == 'admin') {
              req.res.status(401);
              return req.res.send({error: 'Invalid user' });
            }

            const validate = await user.isValidPassword(password);

            if (!validate) {
              req.res.status(401);
              return req.res.send({error: 'Wrong Password' });
            }

            if(!user.isActive){
              req.res.status(401);
              return req.res.send({ error: 'Email not verified.' });
            }

            return done(null, user);
        } catch (error) {
            return done(error);
        }
        }
    )
);

// Passport important middleware for validating tokens from requests and authenticating them.

passport.use(
  new JWTstrategy(
    {
      secretOrKey: process.env.JWT_SECRET,
      jwtFromRequest: ExtractJWT.fromAuthHeaderAsBearerToken()
    },
    async (token, done) => {
      try {
        return done(null, token.user);
      } catch (error) {
        done(error);
      }
    }
  )
);