"use strict";
/*
 * @adonisjs/ace
 *
 * (c) Harminder Virk <virk@adonisjs.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseCommand = void 0;
const prompts_1 = require("@poppinss/prompts");
const helpers_1 = require("@poppinss/utils/build/helpers");
const api_1 = require("@poppinss/cliui/build/api");
const utils_1 = require("@poppinss/utils");
const Generator_1 = require("../Generator");
/**
 * Abstract base class other classes must extend
 */
class BaseCommand {
    /**
     * Accepting AdonisJs application instance and kernel instance
     */
    constructor(application, kernel) {
        this.application = application;
        this.kernel = kernel;
        /**
         * Reference to cli ui
         */
        this.ui = (0, api_1.instantiate)(this.kernel.isMockingConsoleOutput);
        /**
         * The prompt for the command
         */
        this.prompt = this.kernel.isMockingConsoleOutput
            ? new prompts_1.FakePrompt()
            : new prompts_1.Prompt();
        /**
         * Returns the instance of logger to log messages
         */
        this.logger = this.ui.logger;
        /**
         * Reference to the colors
         */
        this.colors = this.logger.colors;
        /**
         * Generator instance to generate entity files
         */
        this.generator = new Generator_1.Generator(this);
    }
    /**
     * Is the current command the main command executed from the
     * CLI
     */
    get isMain() {
        return this.kernel.isMain(this);
    }
    /**
     * Terminal is interactive
     */
    get isInteractive() {
        return this.kernel.isInteractive;
    }
    /**
     * Boots the command by defining required static properties
     */
    static boot() {
        if (this.booted) {
            return;
        }
        this.booted = true;
        (0, utils_1.defineStaticProperty)(this, BaseCommand, {
            propertyName: 'args',
            defaultValue: [],
            strategy: 'inherit',
        });
        (0, utils_1.defineStaticProperty)(this, BaseCommand, {
            propertyName: 'aliases',
            defaultValue: [],
            strategy: 'inherit',
        });
        (0, utils_1.defineStaticProperty)(this, BaseCommand, {
            propertyName: 'flags',
            defaultValue: [],
            strategy: 'inherit',
        });
        (0, utils_1.defineStaticProperty)(this, BaseCommand, {
            propertyName: 'settings',
            defaultValue: {},
            strategy: 'inherit',
        });
        (0, utils_1.defineStaticProperty)(this, BaseCommand, {
            propertyName: 'commandName',
            defaultValue: '',
            strategy: 'define',
        });
        (0, utils_1.defineStaticProperty)(this, BaseCommand, {
            propertyName: 'description',
            defaultValue: '',
            strategy: 'define',
        });
    }
    /**
     * Define an argument directly on the command without using the decorator
     */
    static $addArgument(options) {
        if (!options.propertyName) {
            throw new utils_1.Exception('"propertyName" is required to register a command argument', 500, 'E_MISSING_ARGUMENT_NAME');
        }
        const arg = Object.assign({
            type: options.type || 'string',
            propertyName: options.propertyName,
            name: options.name || options.propertyName,
            required: options.required === false ? false : true,
        }, options);
        this.args.push(arg);
    }
    /**
     * Define a flag directly on the command without using the decorator
     */
    static $addFlag(options) {
        if (!options.propertyName) {
            throw new utils_1.Exception('"propertyName" is required to register command flag', 500, 'E_MISSING_FLAG_NAME');
        }
        const flag = Object.assign({
            name: options.name || helpers_1.string.snakeCase(options.propertyName).replace(/_/g, '-'),
            propertyName: options.propertyName,
            type: options.type || 'boolean',
        }, options);
        this.flags.push(flag);
    }
    /**
     * Execute the command
     */
    async exec() {
        const hasRun = typeof this.run === 'function';
        const hasHandle = typeof this.handle === 'function';
        let commandResult;
        /**
         * Print depreciation warning
         */
        if (hasHandle) {
            process.emitWarning('DeprecationWarning', `${this.constructor.name}.handle() is deprecated. Define run() method instead`);
        }
        /**
         * Run command and catch any raised exceptions
         */
        try {
            /**
             * Run prepare method when exists on the command instance
             */
            if (typeof this.prepare === 'function') {
                await this.application.container.callAsync(this, 'prepare', []);
            }
            /**
             * Execute the command handle or run method
             */
            commandResult = await this.application.container.callAsync(this, hasRun ? 'run' : 'handle', []);
        }
        catch (error) {
            this.error = error;
        }
        let errorHandled = false;
        /**
         * Run completed method when exists
         */
        if (typeof this.completed === 'function') {
            errorHandled = await this.application.container.callAsync(this, 'completed', []);
        }
        /**
         * Throw error when error exists and the completed method didn't
         * handled it
         */
        if (this.error && !errorHandled) {
            throw this.error;
        }
        return commandResult;
    }
    /**
     * Register an onExit handler
     */
    onExit(handler) {
        this.exitHandler = handler;
        return this;
    }
    /**
     * Trigger exit
     */
    async exit() {
        if (typeof this.exitHandler === 'function') {
            await this.exitHandler();
        }
        await this.kernel.exit(this);
    }
}
exports.BaseCommand = BaseCommand;
