const { Middleware } = require('libflitter')

class APIRouteMiddleware extends Middleware {
    static get services() {
        return [...super.services, 'models']
    }

    async test(req, res, next, { allow_token = true, allow_user = true }) {
        if ( !req.additional_api_log_data ) req.additional_api_log_data = {}

        // First, check if there is a user in the session.
        if ( allow_user && req.user ) {
            req.additional_api_log_data.authorized_by = 'user'
            return next()
        } else if ( allow_token ) {
            if ( !req.oauth ) req.oauth = {}
            req.additional_api_log_data.attempted_token_auth = true

            return req.app.oauth2.authorise()(req, res, async e => {
                if ( e ) return next(e)

                req.additional_api_log_data.authorized_by = 'token'

                // Look up the OAuth2 client an inject it into the route
                if ( req.user && req.user.id ) {
                    const User = this.models.get('auth:User')
                    const user = await User.findById(req.user.id)
                    if ( !user )
                        return res.status(401)
                            .message('The user this token is associated with no longer exists.')
                            .api()

                    req.user = user
                    req.is_auth = true

                    // Look up the token and the associated client
                    const Oauth2BearerToken = this.models.get('auth::Oauth2BearerToken')
                    const Client = this.models.get('oauth:Client')

                    // e.g. "Bearer XYZ".split(' ')[1] -> "XYZ"
                    const bearer = req.headers.authorization.split(' ')[1]
                    const token = await Oauth2BearerToken.findOne({ accessToken: bearer })
                    if ( !token )
                        return res.status(401)
                            .message('Unable to lookup OAuth2 token.')
                            .api()

                    const client = await Client.findOne({uuid: token.clientID})
                    if ( !client )
                        return res.status(401)
                            .message('This OAuth2 client is no longer authorized.')
                            .api()

                    req.additional_api_log_data.token_client_id = client.uuid
                    req.additional_api_log_data.token = bearer

                    req.oauth.token = token
                    req.oauth.client = client
                } else
                    return res.status(401)
                        .message('Unable to lookup user associated with that token.')
                        .api()

                next()
            })
        } else {
            return res.status(401).api()
        }
    }
}

module.exports = exports = APIRouteMiddleware
