import Hook from './Hook';

/**
 * @class HooksChain
 * @description Class representing a chain of hooks that execute in sequence.
 * Each hook updates until completion, after which the next hook in the queue starts.
 */
class HooksChain
{
    private hooksQueue: Hook[];
    private currentHookIndex: number;
    private onComplete: (() => void) | null;
    private chainCompleted: boolean;

    /**
     * @class
     */
    constructor()
    {
        this.hooksQueue = [];
        this.currentHookIndex = 0;
        this.onComplete = null;
        this.chainCompleted = false; // Flag to track if the chain has completed
    }

    /**
     * Adds a hook to the end of the chain.
     * @param {Hook} hook - The hook to add to the chain.
     * @returns {HooksChain} - Returns the instance for chaining.
     */
    addHook(hook: Hook): HooksChain
    {
        this.hooksQueue.push(hook);

        return this; // Return instance for chaining
    }

    /**
     * Sets the onComplete callback to execute when all hooks in the chain are complete.
     * @param {() => void} callback - Callback to execute on completion.
     * @returns {HooksChain} - Returns the instance for chaining.
     */
    setOnComplete(callback: () => void): HooksChain
    {
        this.onComplete = callback;

        return this; // Return instance for chaining
    }

    /**
     * Updates the current active hook. If the current hook is complete,
     * it moves to the next hook in the queue.
     * @param {number} dt - Delta time since the last update in milliseconds.
     */
    update(dt: number): void
    {  
        if (this.hooksQueue.length === 0 || !this.hooksQueue) return;

        const currentHook = this.hooksQueue[this.currentHookIndex];

        currentHook.update(dt);

        if (currentHook.isComplete())
        {
            if (currentHook.onComplete)
            {
                currentHook.onComplete();
            }
            this.currentHookIndex++;
        }

        if (this.isComplete())
        {
            if (this.onComplete && !this.chainCompleted)
            {
                this.onComplete();
                this.chainCompleted = true; // Ensure onComplete is called only once
            }
        }
    }

    /**
     * Checks if all hooks in the chain have been completed.
     * @returns {boolean} - Returns `true` if the entire chain is complete, otherwise `false`.
     */
    isComplete(): boolean
    {
        return this.currentHookIndex >= this.hooksQueue.length;
    }

    /** Resets the chain, clearing all hooks and resetting the index. */
    reset(): void
    {
        this.hooksQueue = [];
        this.currentHookIndex = 0;
        this.chainCompleted = false; // Reset the completion flag
    }
}

export default HooksChain;
