"use strict";
/*
 * @poppinss/cliui
 *
 * (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.TaskManager = void 0;
const index_1 = require("./index");
const Verbose_1 = require("./Renderers/Verbose");
const Minimal_1 = require("./Renderers/Minimal");
/**
 * Default set of options
 */
const DEFAULTS = {
    colors: true,
    interactive: true,
    verbose: false,
};
/**
 * Exposes the API to create a group of tasks and run them in sequence
 */
class TaskManager {
    constructor(options, testing = false) {
        this.testing = testing;
        /**
         * A set of created tasks
         */
        this.tasks = [];
        /**
         * State of the tasks manager
         */
        this.state = 'idle';
        this.options = { ...DEFAULTS, ...options };
        this.instantiateRenderer();
    }
    /**
     * Instantiates the tasks renderer
     */
    instantiateRenderer() {
        const rendererOptions = {
            colors: this.options.colors,
            interactive: this.options.interactive,
        };
        /**
         * Using verbose render when verbose option is true or terminal is not
         * interactive
         */
        if (this.options.verbose || this.testing || !this.options.interactive) {
            this.renderer = new Verbose_1.VerboseRenderer(rendererOptions, this.testing);
            return;
        }
        /**
         * Otheriwse using the minimal renderer
         */
        this.renderer = new Minimal_1.MinimalRenderer(rendererOptions, this.testing);
    }
    /**
     * Run a given task. The underlying code assumes that tasks are
     * executed in sequence.
     */
    async runTask(index) {
        const task = this.tasks[index];
        if (!task) {
            return;
        }
        /**
         * Start the underlying task
         */
        task.task.start();
        /**
         * Method to invoke when callback has been completed
         */
        const complete = async (message) => {
            if (task.task.state !== 'running') {
                return;
            }
            task.task.complete(message);
            await this.runTask(index + 1);
        };
        /**
         * Method to invoke when callback has been failed
         */
        const fail = async (message) => {
            if (task.task.state !== 'running') {
                return;
            }
            this.error = message;
            this.state = 'failed';
            task.task.fail(message);
        };
        /**
         * Invoke callback
         */
        try {
            await task.callback(this.renderer.logger, { complete, fail });
        }
        catch (error) {
            await fail(error);
        }
    }
    /**
     * Register a new task
     */
    add(title, callback) {
        this.tasks.push({ task: new index_1.Task(title), callback });
        return this;
    }
    /**
     * Define a custom logging renderer. Logs to "stdout" and "stderr"
     * by default
     */
    useRenderer(renderer) {
        this.renderer.useRenderer(renderer);
        return this;
    }
    /**
     * Run tasks
     */
    async run() {
        if (this.state !== 'idle') {
            return;
        }
        this.state = 'running';
        this.renderer.tasks(this.tasks.map(({ task }) => task)).render();
        await this.runTask(0);
        if (this.state === 'running') {
            this.state = 'succeeded';
        }
    }
}
exports.TaskManager = TaskManager;
