const Controller = require('libflitter/controller/Controller')
const { PageType } = require('../../../enum')

/*
 * Menu Controller
 * -------------------------------------------------------------
 * Put some description here!
 */
class Menu extends Controller {
    static get services() {
        return [...super.services, 'models']
    }

    async get_items(req, res) {
        const virtual_root = req.query.virtualRootPageId
        const Page = this.models.get('api:Page')
        const page_only = req.query.type === 'page'

        if ( !virtual_root ) {
            return this.get_top_level_menu(req, res);
        } else {
            const root_page = await Page.findOne({ UUID: virtual_root })
            if ( !root_page || !(await root_page.is_accessible_by(req.user, 'view')) ) {
                return res.status(404)
                    .message('Invalid virtual root page ID.')
                    .api()
            }

            const nodes = await this._build_menu_object(root_page, [], page_only)
            const menu = []

            const virtual_page = {
                id: root_page.UUID,
                children: [...(await root_page.get_menu_items(page_only)), ...nodes],
                name: root_page.is_shared() ? root_page.Name + ' ⁽ˢʰᵃʳᵉᵈ⁾' : root_page.Name,
                shared: root_page.is_shared(),
                type: PageType.Note,
            };

            menu.push({
                id: 0,
                name: 'Virtual Tree Root',
                children: [virtual_page],
                noDelete: true,
                noChildren: true,
                virtual: true,
                type: PageType.Branch,
            })

            return res.api(menu)
        }
    }

    async get_top_level_menu(req, res) {
        const Page = this.models.get('api:Page')
        const page_only = req.query.type === 'page'

        // Build the "My Tree" option
        const root_page = await req.user.get_root_page()
        const nodes = await this._build_menu_object(root_page, [], page_only)
        const menu = []

        menu.push({
            id: 0,
            name: 'My Info Tree',
            children: nodes,
            noDelete: true,
            noChildren: true,
            virtual: true,
            type: PageType.Branch,
            userRootPage: true,
        })

        // Get view only shared trees
        const view_only_trees = await Page.find({ shared_users_view: req.user._id })
        const view_only_nodes = []
        for ( const tree of view_only_trees ) {
            if ( !(await tree.is_accessible_by(req.user)) ) continue
            view_only_nodes.push({
                id: tree.UUID,
                name: tree.Name,
                children: await this._build_secure_menu_object(tree, req.user),
                level: await tree.access_level_for(req.user),
                type: tree.PageType || PageType.Note,
            })
        }

        // Get update, view shared trees
        const update_trees = await Page.find({ shared_users_update: req.user._id })
        const update_nodes = []
        for ( const tree of update_trees ) {
            if ( !(await tree.is_accessible_by(req.user)) ) continue
            update_nodes.push({
                id: tree.UUID,
                name: tree.Name,
                children: await this._build_secure_menu_object(tree, req.user),
                level: await tree.access_level_for(req.user),
                type: tree.PageType || PageType.Note,
            })
        }

        // Get update, view, manage shared trees
        const manage_trees = await Page.find({ shared_users_manage: req.user._id })
        const manage_nodes = []
        for ( const tree of manage_trees ) {
            if ( !(await tree.is_accessible_by(req.user)) ) continue
            manage_nodes.push({
                id: tree.UUID,
                name: tree.Name,
                children: await this._build_secure_menu_object(tree, req.user),
                level: await tree.access_level_for(req.user),
                type: tree.PageType || PageType.Note,
            })
        }

        menu.push({
            id: 0,
            name: 'Trees Shared With Me',
            children: [...view_only_nodes, ...update_nodes, ...manage_nodes],
            noDelete: true,
            noChildren: true,
            virtual: true,
            type: PageType.Branch,
        })

        return res.api(menu)
    }

    async move_node(req, res, next) {
        const Page = this.models.get('api:Page');

        if ( !req.body.MovedPageId ) {
            return res.status(400)
                .message('Missing MovedPageId.')
                .api()
        }

        if ( !req.body.ParentPageId && req.body.ParentPageId !== 0 ) {
            return res.status(400)
                .message('Missing ParentPageId.')
                .api()
        }

        const moved_page = await Page.findOne({ UUID: req.body.MovedPageId, Active: true })
        if ( !moved_page || !(await moved_page.is_accessible_by(req.user, 'manage')) ) {
            return res.status(400)
                .message('You do not have permission to move this page.')
                .api()
        }

        const parent_page = req.body.ParentPageId === 0 ? await req.user.get_root_page()
            : await Page.findOne({ UUID: req.body.ParentPageId, Active: true })

        if ( !parent_page || !(await parent_page.is_accessible_by(req.user, 'manage')) ) {
            return res.status(400)
                .message('You do not have permission to move into that page.')
                .api()
        }

        // For now, disallow moving pages between users
        if ( `${moved_page.OrgUserId}` !== `${parent_page.OrgUserId}` ) {
            return res.status(400)
                .message('Moving pages between user accounts is not supported at this time.')
                .api()
        }

        if ( !moved_page.ParentId || moved_page.ParentId === '0' ) {
            return res.status(400)
                .message('You cannot move a root page node.')
                .api()
        }

        const old_parent = await moved_page.parent
        moved_page.ParentId = parent_page.UUID;
        old_parent.ChildPageIds = old_parent.ChildPageIds.filter(x => x !== moved_page.UUID);
        parent_page.ChildPageIds.push(moved_page.UUID);

        await parent_page.save();
        await moved_page.save();
        await old_parent.save();
        return res.api();
    }

    async _build_menu_object(parent_node, arr= [], page_only = false) {
        const children = await this.models.get('api:Page').find({UUID: {$in: parent_node.ChildPageIds}})
        if ( children ) {
            for ( const child of children ) {
                arr.push({
                    id: child.UUID,
                    name: child.is_shared() ? child.Name + ' ⁽ˢʰᵃʳᵉᵈ⁾' : child.Name,
                    shared: child.is_shared(),
                    children: [...(await child.get_menu_items(page_only)), ...(await this._build_menu_object(child, [], page_only))],
                    type: child.PageType || PageType.Note,
                })
            }
        }

        return arr
    }

    async _build_secure_menu_object(parent_node, user, arr = []) {
        const children = await parent_node.childPages
        if ( children ) {
            for ( const child of children ) {
                if ( !(await child.is_accessible_by(user)) ) continue
                arr.push({
                    id: child.UUID,
                    name: child.Name,
                    children: await this._build_secure_menu_object(child, user),
                    level: await child.access_level_for(user),
                    type: child.PageType || PageType.Note,
                })
            }
        }
        return arr
    }

}

module.exports = exports = Menu
