const { Middleware } = require('libflitter')
const moment = require('moment')
const uuid = require('uuid').v4

class TrustManager {
    assume_trust = false

    constructor(request, response) {
        this.request = request
        this.response = response
        this.init_store()
    }

    init_store() {
        if ( !Array.isArray(this.request.session.trust_tokens) ) {
            this.request.session.trust_tokens = []
        }

        const now = moment()
        this.request.session.trust_tokens = this.request.session.trust_tokens.filter(x => {
            return moment(new Date(x.expires)) > now
        })

        this.assume_trust = !!this.request.session.trust_assume_trust
    }

    assume() {
        this.request.session.trust_assume_trust = true
        this.assume_trust = true
    }

    unassume() {
        this.request.session.trust_assume_trust = false
        this.assume_trust = false
        this.purge()
    }

    init_flow(scope, next) {
        this.request.session.trust_flow = { scope, next, in_progress: false, requested: `${new Date}` }
    }

    has_flow() {
        const flow = this.request.session?.trust_flow
        return flow && flow.scope && flow.next && moment(new Date(flow.requested)) < moment(new Date(flow.requested)).add('20', 'minutes')
    }

    flow_scope() {
        if ( this.has_flow() ) {
            return this.request.session.trust_flow.scope
        }
    }

    flow() {
        if ( this.has_flow() ) {
            return this.request.session.trust_flow.next
        }
    }

    start() {
        delete this.request.session.user_id
        const grant_token = uuid()
        this.request.session.trust_flow.grant_token = grant_token
        this.request.session.trust_flow.in_progress = true
        this.request.session.trust_flow.started = `${new Date}`
        return grant_token
    }

    check_grant(grant_token) {
        return grant_token === this.request.session?.trust_flow?.grant_token
    }

    end() {
        const next = this.request.session?.trust_flow?.next
        delete this.request.session.trust_flow
        return next
    }

    in_progress() {
        const flow = this.request.session.trust_flow
        return flow && flow.in_progress && flow.started && moment(new Date(flow.started)) < moment(new Date(flow.started)).add('10', 'minutes')
    }

    has(scope) {
        return this.assume_trust || this.request.session.trust_tokens.some(x => x.scope === scope)
    }

    grant(scope) {
        this.request.session.trust_tokens.push({
            scope,
            expires: moment().add('1', 'hour').toDate().toString(),
        })
    }

    deplete(scope) {
        this.request.session.trust_tokens = this.request.session.trust_tokens.filter(x => x.scope !== scope)
    }

    purge() {
        this.end()
        this.request.session.trust_tokens = []
    }
}

class TrustTokenUtilityMiddleware extends Middleware {
    async test(req, res, next, args = {}) {
        if ( req.session ) {
            req.trust = new TrustManager(req, res)
        }

        return next()
    }
}

module.exports = exports = TrustTokenUtilityMiddleware
