const { Controller } = require('libflitter')

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

    async create(req, res, next) {
        const FileBox = this.models.get('api:files:FileBox')

        if ( !req.body.name ) {
            return res.message('Missing required field: name')
                .status(400)
                .api()
        }

        if ( req.body.rootUUID ) {
            const root = await FileBox.findOne({
                active: true,
                UUID: req.body.rootUUID,
            })

            if ( !root || root.nodeId !== req.form.node.UUID ) {
                return res.status(400)
                    .message('Invalid rootUUID.')
                    .api()
            }
        }

        if ( req.body.parentUUID ) {
            if ( !req.body.rootUUID ) {
                return res.status(400)
                    .message('File boxes with a parent MUST also have a root.')
                    .api()
            }

            const parent = await FileBox.findOne({
                active: true,
                UUID: req.body.parentUUID,
            })

            if ( !parent || parent.nodeId !== req.form.node.UUID ) {
                return res.status(400)
                    .message('Invalid parentUUID')
                    .api()
            }
        }

        const box = new FileBox({
            name: req.body.name,
            pageId: req.form.page.UUID,
            nodeId: req.form.node.UUID,
        })

        if ( req.body.rootUUID ) {
            box.rootUUID = req.body.rootUUID
        }

        if ( req.body.parentUUID ) {
            box.parentUUID = req.body.parentUUID
        }

        await box.save()

        if ( !req.body.rootUUID && !box.rootUUID ) {
            box.rootUUID = box.UUID
            await box.save()
        }

        return res.api(await box.to_api())
    }

    async update(req, res, next) {
        const FileBox = this.models.get('api:files:FileBox')
        const { file_box, page, node } = req.form

        if ( req.body.name ) {
            file_box.name = req.body.name
        }

        if ( req.body.parentUUID && req.body.parentUUID !== file_box.parentUUID ) {
            const new_parent = await FileBox.findOne({
                UUID: req.body.parentUUID,
                active: true,
                rootUUID: file_box.rootUUID,
                pageId: page.UUID,
                nodeId: node.UUID,
            })

            if ( !new_parent || new_parent.UUID === file_box.UUID ) {
                return res.status(400)
                    .message('Invalid parentUUID.')
                    .api()
            }

            file_box.parentUUID = new_parent.UUID
        }

        await file_box.save()
        return res.api(await file_box.to_api())
    }

    async update_file(req, res, next) {
        const FileBox = this.models.get('api:files:FileBox')
        const { file_box, file } = req.form

        if ( req.body.name ) {
            file.original_name = req.body.name
        }

        if ( req.body.parentUUID && req.body.parentUUID !== file_box.UUID ) {
            const new_parent = await FileBox.findOne({
                active: true,
                UUID: req.body.parentUUID,
                rootUUID: file_box.rootUUID,
            })

            if ( !new_parent ) {
                return res.status(400)
                    .message('Invalid parentUUID.')
                    .api()
            }

            file_box.fileIds = file_box.fileIds.filter(x => `${x}` !== `${file.id}`)
            new_parent.fileIds.push(file.id)
            await new_parent.save()
            await file_box.save()
        }

        await file.save()
        return res.api(this.file_to_api(file))
    }

    async download_file(req, res, next) {
        const { file_box, file } = req.form
        return file.send(res)
    }

    async upload_files(req, res, next) {
        const { file_box } = req.form

        // const n_files = Object.values(req.uploads).length

        for ( const key in req.uploads ) {
            if ( !req.uploads.hasOwnProperty(key) ) continue
            if ( !key.startsWith('uploaded_file_') ) continue

            file_box.fileIds.push(req.uploads[key].id)
        }

        await file_box.save()
        return res.api()
    }

    async get_box(req, res, next) {
        return res.api(await req.form.file_box.to_api())
    }

    async get_children(req, res, next) {
        const { file_box } = req.form
        const children = await file_box.children()
        return res.api(await Promise.all(children.map(x => x.to_api())));
    }

    async get_files(req, res, next) {
        const { file_box, page } = req.form
        const files = await file_box.files()
        return res.api(files.map(x => this.file_to_api(x)))
    }

    async delete_box(req, res, next) {
        const { file_box } = req.form
        file_box.active = false;
        await file_box.save()
        return res.api()
    }

    async delete_file(req, res, next) {
        const { file_box, file } = req.form
        file_box.fileIds = file_box.fileIds.filter(x => `${x}` !== `${file.id}`)
        await file_box.save()
        return res.api()
    }

    file_to_api(file) {
        return {
            type: 'file',
            title: file.original_name,
            mime: file.mime_type,
            uploaded: file.upload_date,
            category: this.get_file_category(file.mime_type),
            id: file.id,
            _id: file._id,
        }
    }

    get_file_category(mime) {
        if ( mime.includes('opendocument.text') || mime.includes('.document') ) {
            return 'document';
        }

        if ( mime.includes('.spreadsheet') || mime.includes('.sheet') ) {
            return 'spreadsheet';
        }

        if ( mime.includes('.presentation') ) {
            return 'presentation';
        }

        if ( mime.includes('image/') ) {
            return 'image';
        }

        if ( mime === 'application/pdf' ) {
            return 'pdf';
        }

        if ( mime.includes('video/') ) {
            return 'video';
        }

        if ( mime.includes('script') ) {
            return 'code';
        }

        if ( mime.includes('text/') ) {
            return 'text';
        }

        return 'other';
    }
}

module.exports = exports = FileBoxController
