const { Controller } = require('libflitter')
const zxcvbn = require('zxcvbn')

class PasswordController extends Controller {
    static get services() {
        return [...super.services, 'auth', 'jobs', 'models', 'activity']
    }

    async get_resets(req, res, next) {
        return res.api(req.user.password_resets.map(x => {
            return {
                reset_on: x.reset_on,
                reason: x.reason,
            }
        }))
    }

    async get_app_passwords(req, res, next) {
        return res.api(req.user.app_passwords.map(x => {
            return {
                created: x.created,
                expires: x.expires,
                active: x.active,
                name: x.name ?? req.T('common.unnamed'),
                uuid: x.uuid,
            }
        }))
    }

    async create_app_password(req, res, next) {
        if ( !req.body.name )
            return res.status(400)
                .message(`${req.T('api.missing_field')} name`)
                .api()

        const { password, record } = await req.user.app_password(req.body.name)
        await req.user.save()
        await this.activity.app_password_created({ req, name: req.body.name })

        return res.api({
            password,
            name: req.body.name,
            uuid: record.uuid,
        })
    }

    async delete_app_password(req, res, next) {
        if ( !req.params.uuid )
            return res.status(400)
                .message(`${req.T('api.missing_field')} uuid`)
                .api()

        const match = req.user.app_passwords.filter(x => x.uuid === req.params.uuid)[0]
        if ( !match )
            return res.status(400)
                .message(req.T('api.app_pw_not_found'))
                .api()

        req.user.app_passwords = req.user.app_passwords.filter(x => x.uuid !== req.params.uuid)
        await req.user.save()
        return res.api()
    }

    async reset_password(req, res, next) {
        if ( !req.body.password )
            return res.status(400)
                .message(`${req.T('api.missing_field')} password`)
                .api()

        // Verify password complexity
        const min_score = 3
        const result = zxcvbn(req.body.password)
        if ( result.score < min_score )
            return res.status(400)
                .message(req.T('auth.password_complexity_fail').replace('MIN_SCORE', min_score))
                .api()

        // Make sure it's not a re-do
        for ( const old_pw of req.user.password_resets ) {
            if ( await old_pw.check(req.body.password) ) {
                return res.status(400)
                    .message(req.T('auth.duplicate_pw'))
                    .api()
            }
        }

        // Create the password reset
        const reset = await req.user.reset_password(req.body.password)
        await req.user.save()
        await this.activity.password_reset({ req, ip: req.ip })
        if ( req.trap.has_trap() && req.trap.get_trap() === 'password_reset' ) await req.trap.end()

        if ( req.session.registrant_flow ) {
            await req.trap.begin('registrant_flow', { session_only: true })
        }

        // invalidate existing tokens and other logins
        await req.user.logout(req)
        await req.user.kickout()
        req.trust.unassume()
        return res.api()
    }

    async request_reset(req, res, next) {
        if ( !req.body.email )
            return res.status(400)
                .message(`${req.T('api.missing_field')} email`)
                .api()

        const User = this.models.get('auth:User')
        const user = await User.findOne({ email: req.body.email })

        if ( user ) {
            const reset_queue = this.jobs.queue('password_resets')
            await reset_queue.add('PasswordReset', { user_id: user.id })
        }

        return res.api({ success: true })
    }
}

module.exports = exports = PasswordController
