const Oauth2Controller = require('flitter-auth/controllers/Oauth2')

/*
 * Handles views, processing, and data retrieval for flitter-auth's
 * built-in OAuth2 server, if it is enabled. Most handlers are inherited
 * from flitter-auth/controllers/Oauth2, but you can override them here
 * as you need.
 */
class Oauth2 extends Oauth2Controller {
    static get services() {
        return [...super.services, 'Vue', 'configs', 'models', 'output']
    }

    async authorize_post(req, res, next) {
        const client = await this._get_authorize_client({query: req.body})
        if ( !client ) return this._uniform(res, req.T('auth.unable_to_authorize'))

        const StarshipClient = this.models.get('oauth:Client')
        const starship_client = await StarshipClient.findOne({ active: true, uuid: client.clientID })

        // Make sure the user has IAM access before proceeding
        const Application = this.models.get('Application')
        const Policy = this.models.get('iam:Policy')
        const application = await Application.findOne({ oauth_client_ids: starship_client.id })
        if ( !application ) {
            this.output.warn(`IAM Denial: OAuth client not associated with an application: ${starship_client.id}`)
            return this.Vue.auth_message(res, {
                message: req.T('saml.no_access').replace('APP_NAME', application.name),
                next_destination: '/dash',
            })
        } else if ( !(await Policy.check_user_access(req.user, application.id)) ) {
            this.output.warn(`IAM Denial: User ${req.user.uid} not authorized to access application: ${application.id}`)
            return this.Vue.auth_message(res, {
                message: req.T('saml.no_access').replace('APP_NAME', application.name),
                next_destination: '/dash',
            })
        }

        req.user.authorize(starship_client)
        await req.user.save()
        return super.authorize_post(req, res, next)
    }

    async authorize_get(req, res, next) {
        const client = await this._get_authorize_client(req)
        if ( !client ) return this._uniform(res, req.T('auth.unable_to_authorize'))
        const uri = new URL(Array.isArray(req.query.redirect_uri) ? req.query.redirect_uri[0] : req.query.redirect_uri)

        const StarshipClient = this.models.get('oauth:Client')
        const starship_client = await StarshipClient.findOne({ active: true, uuid: client.clientID })

        // Make sure the user has IAM access before proceeding
        const Application = this.models.get('Application')
        const Policy = this.models.get('iam:Policy')
        const application = await Application.findOne({ oauth_client_ids: starship_client.id })
        if ( !application ) {
            this.output.warn(`IAM Denial: OAuth client not associated with an application: ${starship_client.id}`)
            return this.Vue.auth_message(res, {
                message: req.T('saml.no_access').replace('APP_NAME', application.name),
                next_destination: '/dash',
            })
        } else if ( !(await Policy.check_user_access(req.user, application.id)) ) {
            this.output.warn(`IAM Denial: User ${req.user.uid} not authorized to access application: ${application.id}`)
            return this.Vue.auth_message(res, {
                message: req.T('saml.no_access').replace('APP_NAME', application.name),
                next_destination: '/dash',
            })
        }

        let state;
        if ( state = (req.query.state || req.body.state) ) {
            state = Array.isArray(req.query.state) ? req.query.state[0] : req.query.state
            const uri_params = new URLSearchParams(uri.params)
            uri_params.set('state', state)
        }

        if ( req.user.has_authorized(starship_client) ) {
            return this.Vue.invoke_action(res, {
                text: 'Grant Access',
                action: 'post',
                params: {
                    redirect_uri: uri.toString(),
                    client_id: client.clientID,
                },
            })
        }

        return res.page('public:message', {
            ...this.Vue.data({
                message: `<h3 class="font-weight-light">Authorize ${client.name}?</h3>
<br>
${req.T('auth.oauth_prompt').replace('CLIENT_NAME', client.name).replace('APP_NAME', this.configs.get('app.name'))}
<br><br><br>
<i><small>${req.T('auth.will_redirect')} ${uri.host}</small></i>`,

                actions: [
                    {
                        text: req.T('common.deny'),
                        action: 'redirect',
                        next: '/dash',
                    },
                    {
                        text: req.T('common.grant'),
                        action: 'post',
                        params: {
                            redirect_uri: uri.toString(),
                            client_id: client.clientID,
                        },
                    },
                ],
            })
        })
    }

}

module.exports = exports = Oauth2
