const { Controller } = require('libflitter')
const FlitterProfileMapper = require('../../classes/saml/FlitterProfileMapper')
const samlp = require('samlp')

class SAMLController extends Controller {
    static get services() {
        return [...super.services, 'saml', 'output', 'Vue', 'configs', 'models']
    }

    async get_metadata(req, res, next) {
        return samlp.metadata({
            issuer: this.saml.config().provider_name,
            cert: await this.saml.public_cert(),
            logoutEndpointPaths: {
                redirect: '/saml/logout',
            },
            redirectEndpointPath: '/saml/sso',
            postEndpointPath: '/saml/sso',
        })(req, res, next)
    }

    async get_sso(req, res, next) {
        const index = await req.saml.participants.issue({ service_provider: req.saml_request.service_provider })

        // Apply the appropriate IAM policy if this SAML SP is associated with an App
        // If the SAML service provider has no associated application, just allow it
        // TODO test this
        const associated_app = await req.saml_request.service_provider.application()
        if ( associated_app ) {
            const Policy = this.models.get('iam:Policy')
            const can_access = await Policy.check_user_access(req.user, associated_app.id)
            if ( !can_access ) {
                return this.Vue.auth_message(res, {
                    message: req.T('saml.no_access').replace('APP_NAME', associated_app.name),
                    next_destination: '/dash',
                })
            }
        }

        return samlp.auth({
            issuer: this.saml.config().provider_name,
            cert: await this.saml.public_cert(),
            key: await this.saml.private_key(),
            getPostURL: (wtrealm, wreply, req, callback) => {
                this.output.debug(`${req.T('saml.redirect_url')} ${req.saml_request.service_provider.acs_url}`)
                return callback(null, req.saml_request.service_provider.acs_url) // fetch this from registered SAML app
            },
            profileMapper: user => new FlitterProfileMapper(user),
            destination: req.saml_request.service_provider.acs_url,
            sessionIndex: index,
        })(req, res, next)
    }

    async post_logout(req, res, next) {
        return res.api({
            saml: req.saml_request,
            body: req.body,
            query: req.query,
        })
    }

    async get_logout(req, res, next) {
        return samlp.logout({
            deflate: true,
            issuer: this.saml.config().provider_name,
            cert: await this.saml.public_cert(),
            key: await this.saml.private_key(),
            protocolBinding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
            clearIdPSession: done => {
                this.output.info(`${req.T('saml.clear_idp_session')} ${req.user.uid.toLowerCase()}`)
                req.saml.participants.clear().then(async () => {
                    if ( this.saml.config().slo.end_coreid_session ) {
                        await req.user.logout(req)

                        // show logout page
                        return this.Vue.auth_message(res, {
                            message: req.T('auth.logged_out'),
                            next_destination: '/',
                        })
                    } else {
                        return this.Vue.auth_message(res, {
                            message: req.T('auth.logged_out'),
                            next_destination: '/',
                        })
                    }
                })
            },
            sessionParticipants: await req.saml.participants.wrapper(),
        })(req, res, next)
    }
}

module.exports = exports = SAMLController
