import * as fs from 'fs-extra';
import * as _ from 'lodash';
import * as path from 'path';

import Configuration from '../../configuration';
import I18nEngine from '../i18n.engine';
import MarkdownToPdfEngine from './markdown-to-pdf.engine';

const PdfPrinter = require('pdfmake');

export class ExportPdfEngine {
    private static instance: ExportPdfEngine;
    private constructor() {}
    public static getInstance() {
        if (!ExportPdfEngine.instance) {
            ExportPdfEngine.instance = new ExportPdfEngine();
        }
        return ExportPdfEngine.instance;
    }

    public export(outputFolder) {
        let fonts = {
            Roboto: {
                normal: path.join(__dirname, '../src/resources/fonts/roboto-v15-latin-regular.ttf'),
                bold: path.join(__dirname, '../src/resources/fonts/roboto-v15-latin-700.ttf'),
                italics: path.join(__dirname, '../src/resources/fonts/roboto-v15-latin-italic.ttf')
            }
        };

        let printer = new PdfPrinter(fonts);

        let docDefinition = {
            info: {
                title: Configuration.mainData.documentationMainName
            },
            content: [],
            styles: {
                header: {
                    fontSize: 18,
                    bold: true,
                    color: '#008cff',
                    margin: [0, 0, 0, 15]
                },
                subheader: {
                    fontSize: 15,
                    bold: true
                }
            }
        };

        docDefinition.content.push({
            text: Configuration.mainData.documentationMainName,
            alignment: 'center',
            bold: true,
            fontSize: 22,
            margin: [10, 350, 10, 270]
        });

        if (!Configuration.mainData.hideGenerator) {
            docDefinition.content.push({
                text: I18nEngine.translate('generated-using'),
                alignment: 'center'
            });
            docDefinition.content.push({
                image: `data:image/jpeg;base64, `,
                width: 70,
                alignment: 'center',
                pageBreak: 'after'
            });
        }

        docDefinition.content.push({
            toc: {
                title: {
                    text: I18nEngine.translate('table-of-contents'),
                    bold: true,
                    alignment: 'center',
                    fontSize: 18,
                    margin: [10, 10, 10, 50]
                },
                numberStyle: {
                    bold: true
                }
            },
            pageBreak: 'after'
        });

        // Add README page if available

        docDefinition.content.push(this.generateMarkdownContent());

        // Add CHANGELOG page if available

        // Add CONTRIBUTING page if available

        // Add LICENSE page if available

        // Add TODO page if available

        // Add Dependencies page if available

        // Add Additional pages if available

        docDefinition.content.push(this.generateModulesContent());

        docDefinition.content.push(this.generateComponentsContent());

        // Classes

        // Injectables

        // Interceptors

        // Guards

        // Interfaces

        // Pipes

        // Miscellaneous

        // Routes

        // Coverage - docDefinition.content.push(...this.coverageEngine.calculateTable());

        let pdfDoc = printer.createPdfKitDocument(docDefinition);

        return new Promise((resolve, reject) => {
            fs.ensureFile(outputFolder + path.sep + 'documentation.pdf', err => {
                if (err) {
                    reject(`Error during pdf generation: ${err}`);
                } else {
                    pdfDoc.pipe(
                        fs.createWriteStream(outputFolder + path.sep + 'documentation.pdf')
                    );
                    pdfDoc.end();
                    resolve();
                }
            });
        });
    }

    private firstCharacterUpperCase(sentence: string): string {
        return sentence.charAt(0).toUpperCase() + sentence.slice(1);
    }

    private generateMarkdownContent() {
        let pages = Configuration.markDownPages;

        let data = [];

        pages.forEach(page => {
            data.push({
                text: `${this.firstCharacterUpperCase(page.name)}`,
                tocItem: true,
                style: 'header'
            });

            let convertedMarkdownObject = MarkdownToPdfEngine.convert(page.data);
            convertedMarkdownObject.margin = [0, 10];

            data.push(convertedMarkdownObject);
        });

        this.insertPageReturn(data);

        return data;
    }

    private insertPageReturn(data) {
        data.push({
            text: ` `,
            margin: [0, 0, 0, 20],
            pageBreak: 'after'
        });
    }

    private generateModulesContent() {
        let data = [];

        data.push({
            text: 'Modules',
            tocItem: true,
            style: 'header'
        });

        _.forEach(Configuration.mainData.modules, module => {
            data.push({
                text: `${module.name}`,
                style: 'subheader',
                margin: [0, 15, 0, 15]
            });

            data.push({
                text: [
                    {
                        text: `Filename : `,
                        bold: true
                    },
                    {
                        text: module.file
                    }
                ],
                margin: [0, 10]
            });

            if (module.rawdescription != '') {
                data.push({
                    text: `Description :`,
                    bold: true,
                    margin: [0, 10]
                });

                data.push({
                    text: `${module.rawdescription}`,
                    margin: [0, 5]
                });
            }

            if (module.declarations.length > 0) {
                data.push({
                    text: `Declarations :`,
                    bold: true,
                    margin: [0, 10]
                });

                let list = { ul: [] };

                _.forEach(module.declarations, declaration => {
                    list.ul.push({
                        text: `${declaration.name}`
                    });
                });

                data.push(list);
            }

            if (module.providers.length > 0) {
                data.push({
                    text: `Providers :`,
                    bold: true,
                    margin: [0, 10]
                });

                let list = { ul: [] };

                _.forEach(module.providers, provider => {
                    list.ul.push({
                        text: `${provider.name}`
                    });
                });

                data.push(list);
            }

            if (module.imports.length > 0) {
                data.push({
                    text: `Imports :`,
                    bold: true,
                    margin: [0, 10]
                });

                let list = { ul: [] };

                _.forEach(module.imports, importRef => {
                    list.ul.push({
                        text: `${importRef.name}`
                    });
                });

                data.push(list);
            }

            if (module.exports.length > 0) {
                data.push({
                    text: `Exports :`,
                    bold: true,
                    margin: [0, 10]
                });

                let list = { ul: [] };

                _.forEach(module.exports, exportRef => {
                    list.ul.push({
                        text: `${exportRef.name}`
                    });
                });

                data.push(list);
            }

            data.push({
                text: ` `,
                margin: [0, 0, 0, 20]
            });
        });

        this.insertPageReturn(data);

        return data;
    }

    private generateComponentsContent() {
        let data = [];

        data.push({
            text: 'Components',
            tocItem: true,
            style: 'header'
        });

        _.forEach(Configuration.mainData.components, component => {
            data.push({
                text: `${component.name}`,
                style: 'subheader',
                margin: [0, 15, 0, 15]
            });

            data.push({
                text: [
                    {
                        text: `Filename : `,
                        bold: true
                    },
                    {
                        text: component.file
                    }
                ],
                margin: [0, 10]
            });

            if (component.rawdescription != '') {
                data.push({
                    text: `Description :`,
                    bold: true,
                    margin: [0, 10]
                });

                data.push({
                    text: `${component.rawdescription}`,
                    margin: [0, 5]
                });
            }

            data.push({
                text: ` `,
                margin: [0, 0, 0, 20]
            });
        });

        this.insertPageReturn(data);

        return data;
    }
}

export default ExportPdfEngine.getInstance();
