const Controller = require('libflitter/controller/Controller')
const { ObjectId } = require("mongodb");
const Page = require("../../../models/api/Page.model")

/*
 * Misc Controller
 * -------------------------------------------------------------
 * Put some description here!
 */
class Misc extends Controller {
    #default_token_grants = ['database']

    static get services() {
        return [...super.services, 'models']
    }

    async get_token(req, res, next) {
        const Token = this.models.get('api:Token')
        const token = await Token.for_user(req.user)
        return res.api(token.token)
    }

    async get_search(req, res, next) {
        if ( !req.query.query ) {
            return res.status(400)
                .message('Missing query.')
                .api()
        }

        const query = String(req.query.query)
        const snip_length = 50

        const Page = this.models.get('api:Page')
        const Node = this.models.get('api:Node')
        const Codium = this.models.get('api:Codium')
        const Database = this.models.get('api:db:Database')
        const FileGroup = this.models.get('api:FileGroup')
        const File = this.models.get('upload::File')

        const all_user_page_ids = (await req.user.get_accessible_pages()).map(x => x.UUID)
        const results = []

        const matching_pages = await Page.find({
            UUID: { $in: all_user_page_ids },
            Active: true,
            $text: { $search: query },
        })

        for ( const page of matching_pages ) {
            results.push({
                title: page.Name,
                short_title: `${page.Name.slice(0, snip_length)}${page.Name.length > snip_length ? '...' : ''}`,
                type: 'page',
                id: page.UUID,
            })
        }

        const matching_nodes = await Node.find({
            PageId: { $in: all_user_page_ids },
            'Value.Mode': { $in: ['norm', 'markdown'] },
            $text: { $search: query }
        })

        for ( const node of matching_nodes ) {
            const page = await node.page
            results.push({
                title: node.Value.Value,
                short_title: `${node.Value.Value.slice(0, snip_length)}${node.Value.Value.length > snip_length ? '...' : ''}`,
                type: node.Value.Mode === 'norm' ? 'node' : 'markdown',
                id: node.UUID,
                associated: {
                    title: page.Name,
                    short_title: `${page.Name.slice(0, snip_length)}${page.Name.length > snip_length ? '...' : ''}`,
                    type: 'page',
                    id: page.UUID,
                }
            })
        }

        const matching_codiums = await Codium.find({
            Active: true,
            PageId: { $in: all_user_page_ids },
            $text: { $search: query },
        });

        for ( const codium of matching_codiums ) {
            const page = await codium.page
            results.push({
                title: codium.code,
                short_title: `${codium.code.slice(0, snip_length)}${codium.code.length > snip_length ? '...' : ''}`,
                type: 'code',
                id: codium.NodeId,
                associated: {
                    title: page.Name,
                    short_title: `${page.Name.slice(0, snip_length)}${page.Name.length > snip_length ? '...' : ''}`,
                    type: 'page',
                    id: page.UUID,
                }
            })
        }

        const matching_dbs = await Database.find({
            Active: true,
            PageId: { $in: all_user_page_ids },
            $text: { $search: query },
        })

        for ( const db of matching_dbs ) {
            const page = await db.page
            results.push({
                title: db.Name,
                short_title: `${db.Name.slice(0, snip_length)}${db.Name.length > snip_length ? '...' : ''}`,
                type: 'db',
                id: db.NodeId,
                associated: {
                    title: page.Name,
                    short_title: `${page.Name.slice(0, snip_length)}${page.Name.length > snip_length ? '...' : ''}`,
                    type: 'page',
                    id: page.UUID,
                }
            })
        }

        const unique = (value, index, self) => {
            return self.indexOf(value) === index
        }

        const all_file_groups = await FileGroup.find({
            PageId: { $in: all_user_page_ids },
        })

        let all_file_ids = []
        const file_id_x_group = {}
        for ( const group of all_file_groups ) {
            group.FileIds.forEach(id => {
                all_file_ids.push(id)
                file_id_x_group[id] = group
            })
        }

        const unique_file_ids = all_file_ids.filter(unique).map(x => File.ObjectId(x))

        const matching_files = await File.find({
            _id: { $in: unique_file_ids },
            $text: { $search: query },
        })

        for ( const file of matching_files ) {
            const group = file_id_x_group[file.id]
            if ( group ) {
                const page = await group.page
                results.push({
                    title: file.original_name,
                    short_title: `${file.original_name.slice(0, snip_length)}${file.original_name.length > snip_length ? '...' : ''}`,
                    type: 'files',
                    id: group.NodeId,
                    associated: {
                        title: page.Name,
                        short_title: `${page.Name.slice(0, snip_length)}${page.Name.length > snip_length ? '...' : ''}`,
                        type: 'page',
                        id: page.UUID,
                    }
                })
            }
        }

        return res.api({results})
    }
}

module.exports = exports = Misc
