const { Middleware } = require('libflitter')
const { ObjectId } = require('mongodb')

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

    // manage, update, view
    async test(req, res, next, { access_level = 'view' }) {
        if ( !req.user ) {
            return res.status(401)
                .message('Unauthenticated session.')
                .api()
        }

        if ( !req.form ) req.form = {}

        // Try to load in the page
        if ( !req.params.PageId ) return next()

        const Page = this.models.get('api:Page')
        const page = await Page.findOne({ UUID: req.params.PageId })
        if ( !page ) {
            return res.status(404)
                .message('Invalid page ID.')
                .api()
        }

        // Make sure the user has access to the given page
        if ( !(await page.is_accessible_by(req.user, access_level)) ) {
            return res.status(401).api()
        }

        req.form.page = page

        // Try to load in the node
        if ( req.params.NodeId ) {
            const Node = this.models.get('api:Node')
            const node = await Node.findOne({ UUID: req.params.NodeId })

            if ( !node || !page.NodeIds.includes(node.UUID) ) {
                return res.status(404)
                    .message('Invalid node ID.')
                    .api()
            }

            req.form.node = node
        }

        // Try to load in the code snippets
        if ( req.params.CodiumId ) {
            const Codium = this.models.get('api:Codium')
            const codium = await Codium.findOne({
                UUID: req.params.CodiumId,
                Active: true,
                PageId: req.params.PageId,
                ...(req.form.node ? {NodeId: req.form.node.UUID} : {}),
            })

            if ( !codium ) {
                return res.status(404)
                    .message('Invalid code snippet ID.')
                    .api()
            }

            req.form.codium = codium
        }

        // Try to load in the database
        if ( req.params.DatabaseId ) {
            const Database = this.models.get('api:db:Database')
            const database = await Database.findOne({
                UUID: req.params.DatabaseId,
                Active: true,
                PageId: req.params.PageId,
                ...(req.form.node ? {NodeId: req.form.node.UUID} : {}),
            })

            if ( !database ) {
                return res.status(404)
                    .message('Invalid database ID.')
                    .api()
            }

            req.form.database = database
        }

        // Try to load in the file group
        if ( req.params.FilesId ) {
            const FileGroup = this.models.get('api:FileGroup')
            const file_group = await FileGroup.findOne({
                UUID: req.params.FilesId,
                PageId: req.params.PageId,
                ...(req.form.node ? {NodeId: req.form.node.UUID} : {}),
            })

            if ( !file_group ) {
                return res.status(404)
                    .message('Invalid file group ID.')
                    .api()
            }

            req.form.file_group = file_group
        }

        // Try to load in the file box
        if ( req.params.FileBoxId ) {
            const FileBox = this.models.get('api:files:FileBox')
            const file_box = await FileBox.findOne({
                UUID: req.params.FileBoxId,
                pageId: req.params.PageId,
                active: true,
            })

            if ( !file_box ) {
                return res.status(404)
                    .message('Invalid file box ID.')
                    .api()
            }

            req.form.file_box = file_box

            if ( req.params.FileBoxFileId ) {
                const File = this.models.get('upload::File')
                if ( !file_box.fileIds.includes(req.params.FileBoxFileId) ) {
                    return res.status(400)
                        .message('Invalid file box file ID.')
                        .api()
                }

                const file = await File.findOne({
                    _id: ObjectId(req.params.FileBoxFileId),
                })

                if ( !file ) {
                    return res.status(400)
                        .message('Invalid file box file ID.')
                        .api()
                }

                req.form.file = file
            }
        }

        return next()
    }
}

module.exports = exports = DataInjectionMiddleware
