const { Middleware } = require('libflitter')

class TrapUtility {
    constructor(req, res, configs) {
        this.request = req
        this.session = req.session
        this.response = res
        this.user = req.user
        this.configs = configs
    }

    async begin(trap_name, { session_only = false }) {
        if ( session_only || !this.user ) {
            this.session.trap = trap_name
        } else {
            this.user.trap = trap_name
            await this.user.save()
        }

        if ( this.config().assume_trust )
            this.request.trust.assume()
    }

    redirect() {
        if ( this.config().assume_trust )
            this.request.trust.assume()
        return this.response.redirect(this.config().redirect_to)
    }

    async end() {
        if ( this.config().assume_trust )
            this.request.trust.unassume()
        if ( this.user ) {
            this.user.trap = ''
            await this.user.save()
        }
        this.session.trap = ''
    }

    has_trap(name = '') {
        if ( name )
            return (this.user && this.user.trap === name) || this.session.trap === name
        return (this.user && this.user.trap) || this.session.trap
    }

    get_trap() {
        if ( this.session.trap ) return this.session.trap
        else if ( this.user ) return this.user.trap
    }

    trap_exists(name) {
        return !!this.configs[name]
    }

    config() {
        return this.configs[this.get_trap()]
    }

    allows(route) {
        const config = this.config()
        const allowed = route.startsWith('/assets') || config.allowed_routes.includes(route.toLowerCase().trim())
        if ( allowed ) return true

        for ( const allowed_route of config.allowed_routes ) {
            console.log('comparing', allowed_route, 'to', route)
            const allowed_parts = allowed_route.split('/')
            const parts = route.split('/')

            let matches = true
            for ( let i = 0; i < allowed_parts.length; i += 1 ) {
                if ( allowed_parts[i] !== parts[i] && allowed_parts[i] !== '*' ) {
                    matches = false
                }
            }

            if ( matches ) {
                console.log('allows true')
                return true
            }
        }

        console.log('allows false')
        return false
    }
}

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

    async test(req, res, next, args = {}) {
        const Setting = this.models.get('Setting')
        req.trap = new TrapUtility(req, res, this.configs.get('traps.types'))

        if (
            !req.trap.has_trap()
            && req.user
            && !req.user.email_verified
            && (await Setting.get('auth.require_email_verify'))
        ) {
            req.session.email_verify_flow = req.originalUrl
            await req.trap.begin('verify_email', { session_only: false })
        }

        if ( !req.trap.has_trap() ) return next()
        else if ( req.trap.allows(req.path) ) return next()
        else return req.trap.redirect()
    }
}

module.exports = exports = TrapsMiddleware
