const Controller = require('libflitter/controller/Controller')
const os = require('os');
const fs = require('fs').promises;
const uuid = require('uuid/v4');
const path = require('path');

/*
 * Export Controller
 * -------------------------------------------------------------
 * Put some description here!
 */
class Export extends Controller {
    static get services() {
        return [...super.services, 'models', 'app']
    }
    /*
     * Serve the main page.
     */
    async json_export(req, res) {
        const Page = this.models.get('api:Page')
        const Node = this.models.get('api:Node')
        const user = req.user
        const pages = await Page.find({ OrgUserId: user._id })

        const ExportData = {}
        for (const page of pages) { //for all pages of the user, generate a copy of the data
            const nodes = await Node.find({ PageId: page.UUID })

            const PageData = { ...page }
            PageData.Nodes = nodes.map(node => { return { ...node } })
            ExportData[page.Name] = PageData
        }
        return res.api(ExportData)
    }
    async markdown_export(req, res) {
        const Page = this.models.get('api:Page')
        const Node = this.models.get('api:Node')
        const user = req.user
        const page0 = await user.get_root_page() //topmost page
        const temp_dir = path.resolve(os.tmpdir(), uuid())

        await fs.mkdir(temp_dir)
        await this._markdown_recurse(page0, temp_dir)

        /* Archive directory */
        const exec = require('child_process').exec;
        exec('cd ' + path.resolve(temp_dir) + '; zip -r archive.zip *', (error) => {
            if (error) {
                console.error(`exec error: ${error}`);
                return res.error(500);
                return;
            }

            return res.sendFile(`${path.resolve(temp_dir, 'archive.zip')}`)
        })
    }

    async _markdown_recurse(root, temp_dir) { //recursive function for creating directory and generating markdown pages
        const fs = require('fs').promises
        const Page = this.models.get('api:Page')
        const child = await Page.find({ UUID: { $in: root.ChildPageIds } })
        for (const page of child) {
            const markdown = await this._generate_markdown(page)
            await fs.writeFile(path.resolve(temp_dir, page.Name.replace(/\s/g, '_')) + '.md', markdown)
            if (page.ChildPageIds && page.ChildPageIds.length) {
                const sub_temp_dir = path.resolve(temp_dir, page.Name.replace(/\s/g, '_'))
                // console.log(sub_temp_dir)
                await fs.mkdir(sub_temp_dir)
                await this._markdown_recurse(page, sub_temp_dir)
            }
        }
    }
    async _generate_markdown(page) { //generate mark down
        const Node = this.models.get('api:Node')
        const nodes = await Node.find({ PageId: page.UUID })
        return nodes.map(x => {
            if (x.Type === 'click_link') {
                return '[' + x.Value.Value + ']' + '(' + x.Value.Value + ')'
            }
            return x.Value.Value
        }).join('\n')
    }
    async html_export(req, res) {
        const Page = this.models.get('api:Page')
        const Node = this.models.get('api:Node')
        const user = req.user
        const pages = await Page.find({ OrgUserId: user._id, ParentId: { $ne: '0' } })
        const mapping = {} //keeps track of html file UUID and file name
        const page0 = await user.get_root_page() //topmost page

        for (const page of pages) {
            const html_name = page.Name.replace(/\s/g, '_') + '.html'
            mapping[page.UUID] = html_name
        }

        const sidebar_html = await this._generate_sidebar(mapping, user) //generates the sidebar contents

        const temp_dir = path.resolve(os.tmpdir(), uuid()) //make temporary directory
        await fs.mkdir(temp_dir)
        /* Generates html files from template */
        for (const page of pages) {
            const fs = require('fs').promises
            const contents = (await fs.readFile(path.resolve(this.app.directories.assets, 'export-template.html'))).toString('utf8')
            const content_html = await this._generate_html(page)
            const page_html = contents.replace('%%CONTENTS%%', content_html).replace('%%SIDEBAR%%', sidebar_html)
            await fs.writeFile(path.resolve(temp_dir, mapping[page.UUID]), page_html)
        }
        /* Archive directory */
        const exec = require('child_process').exec;
        exec('cd ' + path.resolve(temp_dir) + '; zip -r archive.zip *', (error) => {
            if (error) {
                console.error(`exec error: ${error}`);
                return res.error(500);
                return;
            }
            return res.sendFile(`${path.resolve(temp_dir, 'archive.zip')}`)
        })
    }
    async _generate_sidebar(mapping, user) {// the absolutely dreadful method to create, sidebar
        const Page = this.models.get('api:Page')
        const Node = this.models.get('api:Node')
        const virt_root = await user.get_root_page()
        return await this._sidebar_recurse(mapping, virt_root)

    }
    async _sidebar_recurse(mapping, parent) {
        const Page = this.models.get('api:Page')
        const Node = this.models.get('api:Node')
        const children = await Page.find({ ParentId: parent.UUID })
        let base = ''
        for (const child of children) {
            if (child.ChildPageIds.length === 0) {
                base += '<a class="nav-link ml-2" href="' + mapping[child.UUID] + '">' + child.Name + '</a>' //mapping[child.UUID] gives filename
            } else {
                base += '<a class="nav-link ml-2" href="' + mapping[child.UUID] + '">' + child.Name + '</a>'
                base += '<div class="nav nav-pills flex-column ml-2">'
                base += await this._sidebar_recurse(mapping, child)
                base += '</div>'
            }
        }
        return base
    }
    async _generate_html(page) { //generate html page from page and node data
        const Page = this.models.get('api:Page')
        const Node = this.models.get('api:Node')
        const nodes = await Node.find({ PageId: page.UUID })
        return nodes.map(x => { return x.to_html() }).join('\n')
    }
}

module.exports = exports = Export