"use strict";
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var path = require('path');
var fs = require('fs');
var url = require('url');
var querystring = require('querystring');
var http = require('http');
var https = require('https');
var mustache_1 = require('mustache');
var utility_1 = require('./utility');
var template_1 = require('./utility/template');
var fs_1 = require('./utility/fs');
var command_1 = require('@2fd/command');
var pack = require(path.resolve(__dirname, '../package.json'));
var GREY = 'color:grey';
var GREEN = 'color:green';
var GraphQLDocumentor = (function (_super) {
    __extends(GraphQLDocumentor, _super);
    function GraphQLDocumentor() {
        _super.apply(this, arguments);
        this.description = pack.description + ' v' + pack.version;
        this.params = new command_1.NoParams();
        this.flags = [
            new command_1.ValueFlag('configFile', ['--config', '-c'], 'Configuration file [./package.json].', String, './package.json'),
            new command_1.ValueFlag('endpoint', ['--endpoint', '-e'], 'Graphql http enpoint ["https://domain.com/graphql"].'),
            new command_1.ListValueFlag('heades', ['--header', '-x'], 'HTTP header for request (use with --enpoint). ["Authorization=Token cb8795e7"].'),
            new command_1.ListValueFlag('queries', ['--query', '-q'], 'HTTP querystring for request (use with --enpoint) ["token=cb8795e7"].'),
            new command_1.ValueFlag('schemaFile', ['--schema', '-s'], 'Graphql Schema file ["./schema.json"].'),
            new command_1.ListValueFlag('plugins', ['--plugin', '-p'], 'Use plugins [default=graphdoc/plugins/default].'),
            new command_1.ValueFlag('template', ['--template', '-t'], 'Use template [default=graphdoc/template/slds].', String, 'graphdoc/template/slds'),
            new command_1.ValueFlag('output', ['--output', '-o'], 'Output directory.'),
            new command_1.ValueFlag('baseUrl', ['--base-url', '-b'], 'Base url for templates.', String, './'),
            new command_1.BooleanFlag('force', ['--force', '-f'], 'Delete outputDirectory if exists.'),
            new command_1.BooleanFlag('verbose', ['--verbose', '-v'], 'Output more information.'),
            new command_1.BooleanFlag('version', ['--version', '-V'], 'Show graphdoc version.'),
        ];
    }
    GraphQLDocumentor.prototype.action = function (input, output) {
        var graphdocPackage = pack;
        if (input.flags.version)
            return output.log('graphdoc v%s', graphdocPackage.version);
        var projectPackage = this.getProjectPackage(input, output);
        var config = projectPackage.graphdoc;
        var resolveUrl = utility_1.resolveUrlFor(projectPackage.graphdoc.baseUrl);
        var schema = {};
        var plugins = [];
        function error(err, output) {
            output.error('');
            output.error('%c%s', 'color:red', err.message || err);
            if (config.verbose)
                output.error('%c%s', 'color:grey', err.stack || '    NO STACK');
            output.error('');
        }
        if (!config.output)
            return error(new Error('Output (--output, -o) is require'), output);
        this.getSchema(config, output)
            .then(function (result) { return result.data.__schema; })
            .then(function (result) {
            schema = result;
            plugins = projectPackage.graphdoc.plugins
                .map(function (path) {
                if (config.verbose)
                    output.log('%c - plugin: %c%s', GREEN, GREY, path);
                return fs_1.resolve(path);
            })
                .map(function (path) { return require(path).default; })
                .map(function (Plugin) { return new Plugin(result, resolveUrl, graphdocPackage, projectPackage); });
        })
            .then(function () {
            try {
                // throw Error if path not exits
                fs.statSync(config.output);
                if (!config.force) {
                    return Promise.reject(new Error(config.output + ' already exists (delete it or use the --force flag)'));
                }
                else {
                    if (config.verbose) {
                        output.log('%c - deleting: %c%s', GREEN, GREY, config.output);
                    }
                    return fs_1.removeBuildDirectory(config.output)
                        .then(function () { return config.output; });
                }
            }
            catch (err) {
                if (err.code !== 'ENOENT')
                    return Promise.reject(err);
            }
            return config.output;
        })
            .then(function () {
            var assets = Array.prototype.concat.apply([], plugins.map(function (plugin) { return plugin.getAssets(); }));
            if (config.verbose) {
                output.log('%c - creating: %c%s', GREEN, GREY, config.output);
            }
            return fs_1.createBuildDirectory(config.output, config.template, assets);
        })
            .then(function () {
            var files = [
                'index.mustache',
                'main.mustache',
                'nav.mustache',
                'footer.mustache',
            ]
                .map(function (file) { return path.resolve(config.template, file); })
                .map(function (filepath) {
                if (config.verbose)
                    output.log('%c - reading: %c%s', GREEN, GREY, filepath);
                return fs_1.readFile(filepath, 'utf8');
            });
            return Promise.all(files);
        })
            .then(function (templates) {
            return {
                index: templates[0],
                main: templates[1],
                nav: templates[2],
                footer: templates[3]
            };
        })
            .then(function (partials) {
            var filepath = path.resolve(config.output, 'index.html');
            var data = template_1.createData(projectPackage, graphdocPackage, plugins);
            if (config.verbose)
                output.log('%c - creating: %c%s', GREEN, GREY, filepath);
            return fs_1.writeFile(filepath, mustache_1.render(partials.index, data, partials))
                .then(function () { return partials; });
        })
            .then(function (partials) {
            var writing = []
                .concat(schema.types)
                .concat(schema.directives)
                .map(function (type) {
                var filepath = path.resolve(config.output, resolveUrl(type));
                var data = template_1.createData(projectPackage, graphdocPackage, plugins, type);
                if (config.verbose)
                    output.log('%c - creating: %c%s', GREEN, GREY, filepath);
                return fs_1.writeFile(filepath, mustache_1.render(partials.index, data, partials))
                    .then(function () { return filepath; });
            });
            return Promise.all(writing);
        })
            .then(function (result) {
            output.log('%c[OK] created %d files', GREEN, result.length);
        })
            .catch(function (err) { return error(err, output); });
    };
    GraphQLDocumentor.prototype.getProjectPackage = function (input, output) {
        var projectPackage;
        try {
            projectPackage = require(path.resolve(input.flags.configFile));
        }
        catch (err) {
            projectPackage = {};
        }
        projectPackage.graphdoc = Object.assign({}, projectPackage.graphdoc, input.flags);
        projectPackage.graphdoc.plugins = ['graphdoc/plugins/default']
            .concat(projectPackage.graphdoc.plugins);
        projectPackage.graphdoc.template = fs_1.resolve(projectPackage.graphdoc.template);
        projectPackage.graphdoc.output = path.resolve(projectPackage.graphdoc.output);
        projectPackage.graphdoc.version = pack.version;
        return projectPackage;
    };
    GraphQLDocumentor.prototype.getSchema = function (config, output) {
        if (config.schemaFile) {
            if (config.verbose) {
                output.log('%c - loading schema: %c%s', 'color:green', 'color:grey', config.schemaFile);
            }
            return new Promise(function (resolve, reject) {
                try {
                    var schemapath = path.resolve(config.schemaFile);
                    var schema_1 = require(schemapath);
                    resolve(schema_1);
                }
                catch (err) {
                    reject(err);
                }
            });
        }
        else if (config.endpoint) {
            var options_1 = url.parse(config.endpoint);
            options_1.headers = config.heades.reduce(function (result, header) {
                var _a = header.split('=', 2), name = _a[0], value = _a[1];
                result[name] = value;
                return result;
            }, {});
            options_1.path = options_1.path + '?' + querystring.stringify(config.queries.reduce(function (result, query) {
                var _a = query.split('=', 2), name = _a[0], value = _a[1];
                result[name] = value;
                return result;
            }, { query: utility_1.query }));
            var endpoint_1 = url.format(options_1);
            if (config.verbose) {
                output.log('%c - loading schema: %c%s', 'color:green', 'color:grey', endpoint_1);
            }
            return new Promise(function (resolve, reject) {
                var req = (options_1.protocol === 'https:' ? https : http)
                    .request(options_1, function (res) {
                    if (res.statusCode >= 400)
                        return reject(new Error('[' + res.statusCode + '] ' + res.statusMessage + ' on ' + endpoint_1));
                    var schema = '';
                    res.setEncoding('utf8');
                    res.on('data', function (chunk) {
                        schema += chunk;
                    });
                    res.on('end', function () { return resolve(schema); });
                });
                req.on('error', reject);
                req.end();
            })
                .then(function (result) { return JSON.parse(result); });
        }
        else {
            return Promise.reject(new Error('Enpoint (--endpoint, -e) or Schema File (--schemma,-s) are require.'));
        }
    };
    return GraphQLDocumentor;
}(command_1.Command));
exports.GraphQLDocumentor = GraphQLDocumentor;
//# sourceMappingURL=command.js.map