import EventEmitter from 'eventemitter3';
import Activity from './Activity';

/** Serially executes activities and reports failures. */
export default class ActivityRunner extends EventEmitter
{
    private activities: Activity[] = [];

    public isRunning = false;

    public isError = false;

    constructor()
    {
        super();
        window.ARunner = this;
    }

    /**
     * Adds an activity to the queue and starts processing when idle.
     * @param activity
     */
    addActivity(activity: Activity): void
    {
        this.activities.push(activity);
        console.log(`Activity "${activity.name}" added to the queue.`);

        if (!this.isRunning && !this.isError)
        {
            void this.run();
        }
    }

    /** Runs queued activities in order until empty or a failure occurs. */
    async run(): Promise<void>
    {
        if (this.isRunning)
        {
            console.warn('ActivityRunner is already running. Please wait.');

            return;
        }

        if (this.isError)
        {
            console.warn('ActivityRunner is blocked by Error. Please clear');

            return;
        }

        this.isRunning = true;

        while (this.activities.length > 0 && !this.isError)
        {
            const currentActivity = this.activities.shift();

            if (!currentActivity)
            {
                continue;
            }

            try
            {
                console.log(`activity running for ${currentActivity.name}`);
                await currentActivity.execute();
                console.log(`activity complete for ${currentActivity.name}`);
            }
            catch (error)
            {
                this.isError = true;
                this.emit('error', error);

                break;
            }
        }

        this.isRunning = false;
    }

    /** Clears the queue and resets the runner state. */
    clear(): void
    {
        console.warn('ActivityRunner is cleared');
        this.activities = [];
        this.isRunning = false;
        this.isError = false;
    }
}
