/* global WIKI */

const express = require('express')
const ExpressBrute = require('express-brute')
const BruteKnex = require('../helpers/brute-knex')
const router = express.Router()
const moment = require('moment')
const _ = require('lodash')

const bruteforce = new ExpressBrute(new BruteKnex({
  createTable: true,
  knex: WIKI.models.knex
}), {
  freeRetries: 5,
  minWait: 5 * 60 * 1000, // 5 minutes
  maxWait: 60 * 60 * 1000, // 1 hour
  failCallback: (req, res, next) => {
    res.status(401).send('Too many failed attempts. Try again later.')
  }
})

/**
 * Login form
 */
router.get('/login', async (req, res, next) => {
  _.set(res.locals, 'pageMeta.title', 'Login')

  if (req.query.legacy || (req.get('user-agent') && req.get('user-agent').indexOf('Trident') >= 0)) {
    const { formStrategies, socialStrategies } = await WIKI.models.authentication.getStrategiesForLegacyClient()
    res.render('legacy/login', {
      err: false,
      formStrategies,
      socialStrategies
    })
  } else {
    // -> Bypass Login
    if (WIKI.config.auth.autoLogin && !req.query.all) {
      const stg = await WIKI.models.authentication.query().orderBy('order').first()
      const stgInfo = _.find(WIKI.data.authentication, ['key', stg.strategyKey])
      if (!stgInfo.useForm) {
        return res.redirect(`/login/${stg.key}`)
      }
    }
    // -> Show Login
    const bgUrl = !_.isEmpty(WIKI.config.auth.loginBgUrl) ? WIKI.config.auth.loginBgUrl : '/_assets/img/splash/1.jpg'
    res.render('login', { bgUrl, hideLocal: WIKI.config.auth.hideLocal })
  }
})

/**
 * Social Strategies Login
 */
router.get('/login/:strategy', async (req, res, next) => {
  try {
    await WIKI.models.users.login({
      strategy: req.params.strategy
    }, { req, res })
  } catch (err) {
    next(err)
  }
})

/**
 * Social Strategies Callback
 */
router.all('/login/:strategy/callback', async (req, res, next) => {
  if (req.method !== 'GET' && req.method !== 'POST') { return next() }

  try {
    const authResult = await WIKI.models.users.login({
      strategy: req.params.strategy
    }, { req, res })
    res.cookie('jwt', authResult.jwt, { expires: moment().add(1, 'y').toDate() })

    const loginRedirect = req.cookies['loginRedirect']
    if (loginRedirect === '/' && authResult.redirect) {
      res.clearCookie('loginRedirect')
      res.redirect(authResult.redirect)
    } else if (loginRedirect) {
      res.clearCookie('loginRedirect')
      res.redirect(loginRedirect)
    } else if (authResult.redirect) {
      res.redirect(authResult.redirect)
    } else {
      res.redirect('/')
    }
  } catch (err) {
    next(err)
  }
})

/**
 * LEGACY - Login form handling
 */
router.post('/login', bruteforce.prevent, async (req, res, next) => {
  _.set(res.locals, 'pageMeta.title', 'Login')

  if (req.query.legacy || req.get('user-agent').indexOf('Trident') >= 0) {
    try {
      const authResult = await WIKI.models.users.login({
        strategy: req.body.strategy,
        username: req.body.user,
        password: req.body.pass
      }, { req, res })
      req.brute.reset()
      res.cookie('jwt', authResult.jwt, { expires: moment().add(1, 'y').toDate() })
      res.redirect('/')
    } catch (err) {
      const { formStrategies, socialStrategies } = await WIKI.models.authentication.getStrategiesForLegacyClient()
      res.render('legacy/login', {
        err,
        formStrategies,
        socialStrategies
      })
    }
  } else {
    res.redirect('/login')
  }
})

/**
 * Logout
 */
router.get('/logout', async (req, res) => {
  const redirURL = await WIKI.models.users.logout({ req, res })
  req.logout()
  res.clearCookie('jwt')
  res.redirect(redirURL)
})

/**
 * Register form
 */
router.get('/register', async (req, res, next) => {
  _.set(res.locals, 'pageMeta.title', 'Register')
  const localStrg = await WIKI.models.authentication.getStrategy('local')
  if (localStrg.selfRegistration) {
    res.render('register')
  } else {
    next(new WIKI.Error.AuthRegistrationDisabled())
  }
})

/**
 * Verify
 */
router.get('/verify/:token', bruteforce.prevent, async (req, res, next) => {
  try {
    const usr = await WIKI.models.userKeys.validateToken({ kind: 'verify', token: req.params.token })
    await WIKI.models.users.query().patch({ isVerified: true }).where('id', usr.id)
    req.brute.reset()
    if (WIKI.config.auth.enforce2FA) {
      res.redirect('/login')
    } else {
      const result = await WIKI.models.users.refreshToken(usr)
      res.cookie('jwt', result.token, { expires: moment().add(1, 'years').toDate() })
      res.redirect('/')
    }
  } catch (err) {
    next(err)
  }
})

/**
 * Reset Password
 */
router.get('/login-reset/:token', bruteforce.prevent, async (req, res, next) => {
  try {
    const usr = await WIKI.models.userKeys.validateToken({ kind: 'resetPwd', token: req.params.token })
    if (!usr) {
      throw new Error('Invalid Token')
    }
    req.brute.reset()

    const changePwdContinuationToken = await WIKI.models.userKeys.generateToken({
      userId: usr.id,
      kind: 'changePwd'
    })
    const bgUrl = !_.isEmpty(WIKI.config.auth.loginBgUrl) ? WIKI.config.auth.loginBgUrl : '/_assets/img/splash/1.jpg'
    res.render('login', { bgUrl, hideLocal: WIKI.config.auth.hideLocal, changePwdContinuationToken })
  } catch (err) {
    next(err)
  }
})

/**
 * JWT Public Endpoints
 */
router.get('/.well-known/jwk.json', function (req, res, next) {
  res.json(WIKI.config.certs.jwk)
})
router.get('/.well-known/jwk.pem', function (req, res, next) {
  res.send(WIKI.config.certs.public)
})

module.exports = router