"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const pjson = require('../package.json');
const Config = require("@oclif/config");
const Errors = require("@oclif/errors");
const help_1 = require("@oclif/help");
const util_1 = require("util");
const util_2 = require("./util");
/**
 * swallows stdout epipe errors
 * this occurs when stdout closes such as when piping to head
 */
process.stdout.on('error', err => {
    if (err && err.code === 'EPIPE')
        return;
    throw err;
});
/**
 * An abstract class which acts as the base for each command
 * in your project.
 */
class Command {
    constructor(argv, config) {
        this.argv = argv;
        this.config = config;
        this.id = this.ctor.id;
        try {
            this.debug = require('debug')(this.id ? `${this.config.bin}:${this.id}` : this.config.bin);
        }
        catch (_a) {
            this.debug = () => { };
        }
    }
    get ctor() {
        return this.constructor;
    }
    async _run() {
        let err;
        try {
            // remove redirected env var to allow subsessions to run autoupdated client
            delete process.env[this.config.scopedEnvVarKey('REDIRECTED')];
            await this.init();
            return await this.run();
        }
        catch (error) {
            err = error;
            await this.catch(error);
        }
        finally {
            await this.finally(err);
        }
    }
    exit(code = 0) {
        return Errors.exit(code);
    }
    warn(input) {
        Errors.warn(input);
    }
    error(input, options = {}) {
        return Errors.error(input, options);
    }
    log(message = '', ...args) {
        // tslint:disable-next-line strict-type-predicates
        message = typeof message === 'string' ? message : util_1.inspect(message);
        process.stdout.write(util_1.format(message, ...args) + '\n');
    }
    async init() {
        this.debug('init version: %s argv: %o', this.ctor._base, this.argv);
        if (this.config.debug)
            Errors.config.debug = true;
        if (this.config.errlog)
            Errors.config.errlog = this.config.errlog;
        // global['cli-ux'].context = global['cli-ux'].context || {
        //   command: compact([this.id, ...this.argv]).join(' '),
        //   version: this.config.userAgent,
        // }
        const g = global;
        g['http-call'] = g['http-call'] || {};
        g['http-call'].userAgent = this.config.userAgent;
        if (this._helpOverride())
            return this._help();
    }
    parse(options, argv = this.argv) {
        if (!options)
            options = this.constructor;
        return require('@oclif/parser').parse(argv, Object.assign({ context: this }, options));
    }
    async catch(err) {
        if (!err.message)
            throw err;
        if (err.message.match(/Unexpected arguments?: (-h|--help|help)(,|\n)/)) {
            return this._help();
        }
        if (err.message.match(/Unexpected arguments?: (-v|--version|version)(,|\n)/)) {
            return this._version();
        }
        try {
            const { cli } = require('cli-ux');
            const chalk = require('chalk'); // eslint-disable-line node/no-extraneous-require
            cli.action.stop(chalk.bold.red('!'));
        }
        catch (_a) { }
        throw err;
    }
    async finally(_) {
        try {
            const config = require('@oclif/errors').config;
            if (config.errorLogger)
                await config.errorLogger.flush();
            // tslint:disable-next-line no-console
        }
        catch (error) {
            console.error(error);
        }
    }
    _help() {
        const HelpClass = help_1.getHelpClass(this.config);
        const help = new HelpClass(this.config);
        const cmd = Config.Command.toCached(this.ctor);
        if (!cmd.id)
            cmd.id = '';
        let topics = this.config.topics;
        topics = topics.filter((t) => !t.hidden);
        topics = util_2.sortBy(topics, (t) => t.name);
        topics = util_2.uniqBy(topics, (t) => t.name);
        help.showCommandHelp(cmd, topics);
        return this.exit(0);
    }
    _helpOverride() {
        for (const arg of this.argv) {
            if (arg === '--help')
                return true;
            if (arg === '--')
                return false;
        }
        return false;
    }
    _version() {
        this.log(this.config.userAgent);
        return this.exit(0);
    }
}
exports.default = Command;
Command._base = `${pjson.name}@${pjson.version}`;
/** An array of aliases for this command */
Command.aliases = [];
/** When set to false, allows a variable amount of arguments */
Command.strict = true;
Command.parse = true;
Command.parserOptions = {};
/**
 * instantiate and run the command
 * @param {Config.Command.Class} this Class
 * @param {string[]} argv argv
 * @param {Config.LoadOptions} opts options
 * @returns Promise<any>
 */
Command.run = async function (argv, opts) {
    if (!argv)
        argv = process.argv.slice(2);
    const config = await Config.load(opts || (module.parent && module.parent.parent && module.parent.parent.filename) || __dirname);
    const cmd = new this(argv, config);
    return cmd._run(argv);
};
