import { assert } from "../../../../core/assert.js";
import { Behavior } from "../Behavior.js";
import { BehaviorStatus } from "../BehaviorStatus.js";
import { CompositeBehavior } from "./CompositeBehavior.js";

/**
 * Executes all contained behaviors one after another in a sequence, next behaviour in the sequence will not be started until the previous one signal success
 * If any of the contained behaviours fail - the whole sequence fails
 *
 * @author Alex Goldring
 * @copyright Company Named Limited (c) 2026
 */
export class SequenceBehavior extends CompositeBehavior {
    constructor() {
        super();

        /**
         *
         * @type {number}
         * @protected
         */
        this.__currentBehaviourIndex = -1;
        /**
         *
         * @type {BehaviorStatus|number}
         * @private
         */
        this.__currentBehaviourState = BehaviorStatus.Initial;

        /**
         *
         * @type {Behavior}
         * @protected
         */
        this.__currentBehaviour = undefined;
    }

    initialize(context) {
        // console.log('+ SequenceBehavior');

        this.__currentBehaviourIndex = 0;
        this.__currentBehaviour = this.__children[0];

        // allow for empty sequence
        if (this.__currentBehaviour !== undefined) {
            //initialize first behaviour
            this.__currentBehaviour.initialize(context);
        }

        this.__currentBehaviourState = BehaviorStatus.Running;

        super.initialize(context);
    }


    /**
     *
     * @param {number} timeDelta
     * @returns {BehaviorStatus}
     */
    tick(timeDelta) {
        assert.isNonNegativeInteger(this.__currentBehaviourIndex, 'child index');

        const currentBehaviour = this.__currentBehaviour;

        if (currentBehaviour === undefined) {
            // either un-initialized, or an empty sequence
            this.__currentBehaviourState = BehaviorStatus.Succeeded;
            return BehaviorStatus.Succeeded;
        }

        const s = currentBehaviour.tick(timeDelta);

        this.__currentBehaviourState = s;

        if (s !== BehaviorStatus.Succeeded) {
            return s;
        }

        //current behaviour succeeded, move onto the next one
        currentBehaviour.finalize();

        this.__currentBehaviourState = BehaviorStatus.Initial;
        this.__currentBehaviourIndex++;

        if (this.__currentBehaviourIndex < this.__children.length) {
            this.__currentBehaviour = this.__children[this.__currentBehaviourIndex];

            this.__currentBehaviour.initialize(this.context);

            this.__currentBehaviourState = BehaviorStatus.Running;

            return BehaviorStatus.Running;
        } else {
            //all behaviours completed
            return BehaviorStatus.Succeeded;
        }
    }

    finalize() {

        const child_count = this.__children.length;

        if (this.__currentBehaviourIndex !== child_count) {
            //sequence has not been finished

            if (
                this.__currentBehaviour !== undefined
                && this.__currentBehaviourState !== BehaviorStatus.Initial
            ) {
                this.__currentBehaviour.finalize();
            }
        }

        this.__currentBehaviour = undefined;
        this.__currentBehaviourIndex = child_count;

        // console.warn('- SequenceBehavior');
        super.finalize();
    }

    /**
     *
     * @param {Behavior[]} children
     * @return {SequenceBehavior}
     */
    static from(children) {
        const r = new SequenceBehavior();

        r.addChildren(children);

        return r;
    }
}

/**
 * @readonly
 * @type {boolean}
 */
SequenceBehavior.prototype.isSequenceBehavior = true;

SequenceBehavior.typeName = "SequenceBehavior";

