const { Middleware } = require('libflitter')
const { Injectable } = require('flitter-di')
const SAMLParticipantWrapper = require('samlp/lib/sessionParticipants/index')

class SessionParticipantStore extends Injectable {
    static get services() {
        return ['models']
    }

    constructor(request, participants = []) {
        super()
        this.request = request
        this.participants = participants
        this.SessionParticipant = this.models.get('saml:SessionParticipant')
    }

    async issue({ service_provider }) {
        const sp = new this.SessionParticipant({
            service_provider_id: service_provider.id,
            name_id: this.request.user.uid.toLowerCase(),
            // session_index: this.get_index(),
            slo_url: service_provider.slo_url,
            // TODO sp_cert,
        })

        await sp.save()
        this.participants.push(sp)
        this.flush_participants()
        return sp.session_index
    }

    flush_participants() {
        this.request.session.saml_participant_uuids = this.participants.map(x => x.uuid)
    }

    get_index() {
        const i = this.request.session.saml_next_index || 0
        this.request.session.saml_next_index = i + 1
        return i
    }

    async clear() {
        for ( const p of this.participants ) {
            p.active = false
            await p.save()
        }

        this.participants = []
        this.flush_participants()
    }

    async wrapper() {
        const participants = []

        for ( const p of this.participants ) {
            const sp = await this.models.get('saml:ServiceProvider').findById(p.service_provider_id)
            participants.push({
                serviceProviderId: sp.entity_id,
                nameId: p.name_id,
                nameIdFormat: p.name_id_format,
                sessionIndex: p.session_index,
                serviceProviderLogoutURL: p.slo_url,
                // TODO cert
            })
        }

        return new SAMLParticipantWrapper(participants)
    }
}

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

    async test(req, res, next, { flush = false }) {
        const SessionParticipant = this.models.get('saml:SessionParticipant')
        const di = this.app.di()

        if ( !req.saml ) req.saml = {}
        if ( !Array.isArray(req.session.saml_participant_uuids) || flush ) {
            req.saml.participants = di.make(SessionParticipantStore, req)
        } else {
            const sps = await SessionParticipant.find({ uuid: { $in: req.session.saml_participant_uuids } })
            req.saml.participants = di.make(SessionParticipantStore, req, sps)
        }

        next()
    }

}

module.exports = exports = SAMLUtilityMiddleware
