/*************************************************************************
 *
 * Troven CONFIDENTIAL
 * __________________
 *
 *  (c) 2017-2020 Troven Pty Ltd
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Troven Pty Ltd and its licensors,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Troven Pty Ltd
 * and its suppliers and may be covered by International and Regional Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Troven Pty Ltd.
 */

import {
    IOperation,
    IChassisMiddleware,
    IChassisContext,
    APIRequests,
    APIs,
} from "api-service-core";
import * as assert from "assert";
import * as _ from "lodash";
import * as fs from "fs";
import { render } from "api-service-common";
const plantuml = require("node-plantuml");

export default class PlantUML implements IChassisMiddleware {
    name = "plantuml";
    title = "Text Diagrams using PlantUML";

    fn(operation: IOperation, _options: any) {
        false && operation;

        let options = _.extend({ render: {} }, _options);
        let feature = operation.feature || { plantuml: {} };
        let feature_apis: APIRequests = _.extend(
            {},
            feature.plantuml.apis,
            feature.apis
        );
        let context = operation.context;

        let folder = options.folder || ".";
        let self = this;

        let renderer: render = context.plugins.get("render") as render;

        let default_page_context = _.extend(
            {
                markdown: "",
                layout: "default",
                brand: _.extend({}, options.render.brand, feature.brand),
                i18n: _.extend({}, options.render.i18n, feature.i18n),
                pkg: { name: context.pkg.name, version: context.pkg.version },
            },
            renderer.render_options
        );

        return function (req, res, _next) {
            let content_type = req.headers["content-type"];
            let file = folder + "/" + req.params[0];

            let api_params = _.extend(
                {},
                feature.request,
                default_page_context
            );
            let jwt_token = feature.reuseJWT ? req.header("authorization") : "";

            APIs.requests(context, feature_apis, api_params, jwt_token)
                .then((results) => {
                    let page_context = _.extend(default_page_context, results);
                    context.log({
                        code: "plugin:plantuml:render",
                        content_type: content_type,
                        file: file,
                    });

                    switch (content_type) {
                        case "image/svg+xml":
                            self.render(
                                context,
                                file,
                                res,
                                options,
                                "svg",
                                content_type,
                                page_context
                            );
                            break;
                        case "image/png":
                            self.render(
                                context,
                                file,
                                res,
                                options,
                                "png",
                                content_type,
                                page_context
                            );
                            break;
                        default:
                            let type = self.guessFormat(file);
                            self.render(
                                context,
                                type.file,
                                res,
                                options,
                                type.format,
                                type.type,
                                page_context
                            );
                            break;
                    }
                })
                .catch((err) => {
                    res.status(500);
                    res.send({
                        code: "plugin:plantuml:render:failed",
                        error: err.message,
                    });
                });
        };
    }

    guessFormat(file: string): any {
        let ix = file.lastIndexOf(".");
        let extn = file.substring(ix + 1);
        file = file.substring(0, ix);

        switch (extn) {
            case "png":
                return { file: file, format: "png", type: "image/png" };
            case "svg":
                return { file: file, format: "svg", type: "image/svg+xml" };
        }
        return null;
    }

    render(
        context: IChassisContext,
        file: string,
        res: any,
        options: any,
        format: string,
        content_type: string,
        render_context: any
    ) {
        let renderer: render = context.plugins.get("render") as render;
        assert(renderer, "render plugin not installed");

        try {
            renderer.hbs.getPartials().then((partials) => {
                // console.log("page_context: %o --> %o", page_context, partials);
                let text = fs.readFileSync(file, "UTF-8");
                let parsed = renderer.hbs._compileTemplate(text, {
                    partials: partials,
                })(render_context);
                res.set("Content-Type", content_type);
                let gen = plantuml.generate(
                    parsed,
                    _.extend({}, options, { format: format })
                );
                res.status(200);
                gen.out.pipe(res);
            });
        } catch (err) {
            res.status(400);
            res.send({
                code: "plugin:diagram:uml",
                message: err.toString(),
                errors: true,
            });
        }
    }
}
