const jwt = require('jsonwebtoken')
const User = require('./models/User')

function res401(res, message) {
  return res.status(401).json({ message })
}

const authentication = {
  // secret for generating jwt token
  secretKey:
    '6fdd08afdb7ec5b7b83ba5d7635a4ad78a5c9545a9ccd90b0b74299b5ab3a69f640cdd1e0c47655daebe099c96e3172da9be76892f14ef2aec34937757c75f27',
  // check if just logged in (admin-or-user) (middleware)
  isLoggedIn(req, res, next) {
    try {
      const token = req.headers?.authorization
      if (!token) throw new Error('err')
      const decoded = jwt.verify(token.replace(/^Bearer\s/, ''), authentication.secretKey)
      if (!decoded) throw new Error('err')
      else return next()
    } catch (err) {
      return res401(res, 'unauthenticated')
    }
  },
  // check if admin logged in (middleware)
  async isAdmin(req, res, next) {
    try {
      const token = req.headers?.authorization
      if (!token) throw new Error('err')

      const decoded = jwt.verify(token.replace(/^Bearer\s/, ''), authentication.secretKey)
      if (!decoded) throw new Error('err')

      const user = await User.findById(decoded._id)
      if (!user || !user.scope.includes('admin')) throw new Error('err')

      req.user_id = decoded._id
      return next()
    } catch (err) {
      return res401(res, 'unauthorized')
    }
  },
  // check if user logged in (middleware)
  async isUser(req, res, next) {
    try {
      const token = req.headers?.authorization
      if (!token) throw new Error('err')

      const decoded = jwt.verify(token.replace(/^Bearer\s/, ''), authentication.secretKey)
      if (!decoded) throw new Error('err')

      const user = await User.findById(decoded._id)
      if (!user || !user.scope.includes('user')) throw new Error('err')

      req.user_id = decoded._id
      return next()
    } catch (err) {
      return res401(res, 'unauthorized')
    }
  },
  // check if user is agent and add agent id to body(middleware)
  async isAgent(req, res, next) {
    try {
      const token = req.headers?.authorization
      if (!token) throw new Error('err')

      const decoded = jwt.verify(token.replace(/^Bearer\s/, ''), authentication.secretKey)
      if (!decoded) throw new Error('err')

      const user = await User.findById(decoded._id)
      if (!user || !user.isAgent || !user.scope.includes('user')) throw new Error('err')

      req.user_id = decoded._id
      req.agent_id = user.representation_id
      return next()
    } catch (err) {
      return res401(res, 'unauthorized')
    }
  },
  // get user id from token
  getID: req => {
    const token = req.headers?.authorization
    return jwt.verify(token?.replace(/^Bearer\s/, ''), authentication.secretKey, (err, decoded) => {
      if (err) return null
      else return decoded._id
    })
  },
  // check if admin has permission (middleware - web only)
  hasPermission: permission => {
    return async (req, res, next) => {
      try {
        const token = req.headers?.authorization
        if (!token) throw new Error('err')

        const user = await User.findOne({ token })
        if (!user || !user.permissions.includes(permission)) throw new Error('err')
        else return next()
      } catch (err) {
        return res401(res, 'unauthorized')
      }
    }
  }
}

module.exports = authentication
