const SearchService = require('../search/SearchService');
const sharedConstants = require('../../shared/constants/SharedConstants');

const moment = require('moment');
global.moment = moment;

const jsonpath = require('jsonpath-plus');
const handlebars = require('handlebars');
const SearchResultsProcessor = require('../../shared/utils/SearchResultsProcessor');
const utilHttpStatus = require('../../shared/utils/UtilHttpStatus');

const SEARCH_AFTER_SIZE = 10000;

const searchAfterFn = (query, searchAfter, sort, userId) => {
    const options = { 
        filter: query,
        from: 0,
        size: SEARCH_AFTER_SIZE
    };

    if (searchAfter) {
        options.searchAfter = searchAfter;
    }
    
    if (!sort) {
        options.sort = {
            "sort": [ {"systemHeader.serverUpdatedDate": "asc"}]
        };
    }
    
    return SearchService.search(options, userId);
};

const maxSearch = async (query, sort, userId) => {
    let searchAfter = null;
    let total = 0;
    let data = [];
    let result;

    do {
        result = await searchAfterFn(query, searchAfter, sort, userId);
        const hits = result.data.hits.hits;
        total = hits.length;
        if (total === 0) break;

        data = data.concat(hits);
        searchAfter = hits[total - 1].sort;
    } while(total === SEARCH_AFTER_SIZE);

    return { data: { hits: {total: data.length, hits: data }}};
};



exports.searchExport = async (req, res) => {
    let query = req.body;
    let userId = query.userId || req.user.documentId;
    let document = query.document || {};
    let headers = [{ "title": "Document ID", "field": "documentId" }]; // default

    try {
        if (query.headers) {
            headers = query.headers;
        }

        if (typeof document === 'string') {
            document = JSON.parse(document);
        }

        if (query.handlebarsHelpers && query.handlebarsHelpers.length) {
            for (const helper of query.handlebarsHelpers) {
                try {
                    let helpFunc = helper.function;
                    logger.info(helper.name + ' = ' + helpFunc);
                    if (typeof helpFunc === 'string') {
                        helpFunc = new Function('return ' + helpFunc)();
                    }

                    handlebars.registerHelper(helper.name, helpFunc);
                } catch (e) {
                    throw new Error('Invalid function for helper ' + helper.name + ': ' + e.message);
                }
            }
        }

        const searchQuery = query.query;
        if (!searchQuery) {
            throw new Error('Query is not defined!');
        }

        let data;
        if (query.type === sharedConstants.EXPORT_TYPE_PDF) {
            data = await SearchService.search({ filter: searchQuery }, userId);
        } else {
            data = await maxSearch(query.query, query.sort, userId);
        }

        const stripHTML = (text) => {
            const shouldStripHTML = query.stripHTML === true;
            if (!text || typeof text !== 'string' || !shouldStripHTML) {
                return text;
            }

            text = text.replace(/<[^>]*>?/gm, '');
            return text;
        };

        const processRow = (header, doc) => {
            try {
                if (!doc || typeof doc !== 'object') {
                    return doc;
                }

                if (header.cellTemplate) {
                    const context = {};

                    context.row = doc;
                    context.result = doc;

                    context.document = document;
                    context.doc = document;

                    try {
                        const hrefTpl = handlebars.compile(header.cellTemplate);
                        return hrefTpl(context);
                    } catch (e) { }
                }

                var matches = jsonpath.JSONPath({path: header.field, json: doc});
                let value = matches.length > 0 ? matches[0] : null;

                if (!value) {
                    return null;
                }

                if (header.type === 'date' && header.format) {
                    value = moment(value).format(header.format);
                }

                if (header.type === 'url') {
                    const hrefTpl = handlebars.compile(header.href);
                    const url = config.get("urlRoot") + hrefTpl(doc);
                    const excelFormat = `=HYPERLINK("${url}", "${value}")`;
                    const exportMode = header.urlExportMode || query.urlExportMode;

                    switch (exportMode) {
                        case 'textOnly':
                            return value;
                        case 'linkOnly':
                            return url;
                        case 'excelFormat':
                            return excelFormat;
                        default:
                            if (query.type === sharedConstants.EXPORT_TYPE_CSV) {
                                return excelFormat;
                            }

                            return {
                                title: value,
                                type: header.type,
                                href: hrefTpl(doc)
                            };
                    }
                }

                if (header.filter === 'arrayFilter' && header.arrayField) {
                    if (value.length) {
                        let newValue = '';
                        for (const v of value) {
                            if (typeof v === 'object') {
                                var matches =  jsonpath.JSONPath({path: header.arrayField, json: v});
                                if (matches.length > 0) {
                                    newValue += matches[0];
                                }
                            } else {
                                newValue += v;
                            }

                            if (value.indexOf(v) < value.length - 1 && !newValue.endsWith(', ')) {
                                newValue += ', ';
                            }
                        }

                        value = newValue;
                    }
                }

                return value;
            } catch (error) {
                return null;
            }
        };

        let results = [];

        SearchResultsProcessor.processSearchResults(data, doc => { 
            if (query.type === sharedConstants.EXPORT_TYPE_PDF) {
                const record = headers.map(header => stripHTML(processRow(header, doc)));
                results.push(record);
            } else {
                let record = {};
                for (let i = 0; i < headers.length; i++) {
                    const header = headers[i];
                    let title = header.title;
                    if (record[title]) title = title + " ";
                    record[title] = stripHTML(processRow(header, doc));
                }
                results.push(record);            
            }
        }, docs => {
            const doPDF = () => {

                let fileName = query.fileName || 'export.pdf';
                let size = query.size || 'A4';
                let layout = query.layout || 'landscape';
                let fontSize = query.fontSize || 10;
                let headerFontSize = query.headerFontSize || fontSize;
                let margin = query.margin || 25;
                let columnSpacing = query.columnSpacing || 5;
                let rowSpacing = query.rowSpacing || 5;

                const PDFDocument = require('../utils/PdfTable');
                const doc = new PDFDocument({
                    size, layout,
                    margin: +margin
                });

                const table = {
                    headers,
                    rows: results
                };

                doc.table(table, {
                    prepareHeader: () => doc.font('Helvetica-Bold').fontSize(headerFontSize),
                    prepareRow: (row, i) => doc.font('Helvetica').fontSize(fontSize),
                    columnSpacing,
                    rowSpacing
                });

                res.setHeader('Content-disposition', 'inline; filename=' + fileName);
                res.set('Content-Type', 'application/pdf');
                doc.pipe(res);

                doc.end();
            };

            const doCSV = () => {
                const json2csv = require('json2csv').parse;
                let fileName = query.fileName || 'export.csv';
                results = results.length ? results : [headers.reduce((obj, item) => ({ ...obj, [item.title]: '' }), {})];
                const csvString = json2csv(results);
                res.setHeader('Content-disposition', 'inline; filename=' + fileName);
                res.set('Content-Type', 'text/csv');
                res.status(200).send(csvString);
            };

            if (query.type === sharedConstants.EXPORT_TYPE_PDF) {
                doPDF();
            } else {
                doCSV();
            }
        });
    } catch (err) {
        logger.error(err);
        res.status(utilHttpStatus.INTERNAL_SERVER_ERROR).send(err.message);
    }
};
