import logger from '@overleaf/logger'
import passport from 'passport'
import EmailHelper from '../../../../../app/src/Features/Helpers/EmailHelper.mjs'
import { handleAuthenticateErrors } from '../../../../../app/src/Features/Authentication/AuthenticationErrors.mjs'
import AuthenticationController from '../../../../../app/src/Features/Authentication/AuthenticationController.mjs'
import LDAPAuthenticationManager from './LDAPAuthenticationManager.mjs'

const LDAPAuthenticationController = {
  passportLogin(req, res, next) {
    // This function is middleware which wraps the passport.authenticate middleware,
    // so we can send back our custom `{message: {text: "", type: ""}}` responses on failure,
    // and send a `{redir: ""}` response on success
    passport.authenticate(
      'ldapauth',
      { keepSessionInfo: true },
      async function (err, user, info, status) {
        if (err) { //we cannot be here as long as errors are treated as fails
          return next(err)
        }
        if (user) {
          // `user` is either a user object or false
          AuthenticationController.setAuditInfo(req, {
            method: 'LDAP password login',
          })

          try {
            await AuthenticationController.promises.finishLogin(user, req, res)
	    res.status(200)
	    return
          } catch (err) {
            return next(err)
          }
        } else {
          if (status != 401) {
            logger.warn(status, 'LDAP: ' + info.message)
          }
          if (EmailHelper.parseEmail(req.body.email)) return next() //Try local authentication
          if (info.redir != null) {
            return res.json({ redir: info.redir })
          } else {
            res.status(status || info.status || 401)
            delete info.status
            info.type = 'error'
            info.key = 'invalid-password-retry-or-reset'
            const body = { message: info }
            const { errorReason } = info
            if (errorReason) {
              body.errorReason = errorReason
              delete info.errorReason
            }
            return res.json(body)
          }
        }
      }
    )(req, res, next)
  },
  async doPassportLogin(req, profile, done) {
    let user, info
    try {
      ;({ user, info } = await LDAPAuthenticationController._doPassportLogin(
        req,
        profile
      ))
    } catch (error) {
      return done(error)
    }
    return done(undefined, user, info)
  },
  async _doPassportLogin(req, profile) {
    const { fromKnownDevice } = AuthenticationController.getAuditInfo(req)
    const auditLog = {
      ipAddress: req.ip,
      info: { method: 'LDAP password login', fromKnownDevice },
    }

    let user, isPasswordReused
    try {
      user = await LDAPAuthenticationManager.promises.findOrCreateUser(profile, auditLog)
    } catch (error) {
      return {
        user: false,
        info: handleAuthenticateErrors(error, req),
      }
    }
    if (user && AuthenticationController.captchaRequiredForLogin(req, user)) {
      return {
        user: false,
        info: {
          text: req.i18n.translate('cannot_verify_user_not_robot'),
          type: 'error',
          errorReason: 'cannot_verify_user_not_robot',
          status: 400,
        },
      }
    } else if (user) {
      user.externalAuth = 'ldap'
      return { user, info: undefined }
    } else { //we cannot be here, something is terribly wrong
      logger.debug({ email : profile.mail }, 'failed LDAP log in')
      return {
        user: false,
        info: {
          type: 'error',
          text: 'Unknown error',
          status: 500,
        },
      }
    }
  },
}

export default LDAPAuthenticationController
