import { Blackboard } from "./BehaviorTree.js";
export class State {
    id;
    name;
    transitions = [];
    onEnter;
    onUpdate;
    onExit;
    constructor(id, name = id) {
        this.id = id;
        this.name = name;
    }
    addTransition(targetState, condition, priority = 0, name = `${this.id}->${targetState}`) {
        this.transitions.push({ targetState, condition, priority, name });
        this.transitions.sort((left, right) => right.priority - left.priority || left.name.localeCompare(right.name));
        return this;
    }
}
export class StateMachine {
    blackboard;
    states = new Map();
    history = [];
    maxHistorySize;
    current;
    previous;
    running = false;
    tickCounter = 0;
    transitionCounter = 0;
    lastTrace = [];
    constructor(blackboard = new Blackboard(), options = {}) {
        this.blackboard = blackboard;
        this.maxHistorySize = options.maxHistorySize ?? 12;
    }
    addState(state) {
        if (this.states.has(state.id))
            throw new Error(`State already registered: ${state.id}`);
        this.states.set(state.id, state);
        return this;
    }
    getState(id) {
        return this.states.get(id);
    }
    start(stateId) {
        const state = this.requireState(stateId);
        this.running = true;
        this.current = state;
        this.previous = undefined;
        this.lastTrace = [`enter:${state.id}`];
        state.onEnter?.(this.blackboard);
        return this.snapshot();
    }
    stop() {
        if (this.current) {
            this.current.onExit?.(this.blackboard);
            this.lastTrace = [`exit:${this.current.id}`, "stop"];
        }
        else {
            this.lastTrace = ["stop"];
        }
        this.running = false;
        this.previous = this.current;
        this.current = undefined;
        return this.snapshot();
    }
    update(deltaSeconds) {
        this.tickCounter += 1;
        this.lastTrace = [];
        if (!this.running || !this.current) {
            this.lastTrace.push("idle");
            return this.snapshot();
        }
        this.current.onUpdate?.(Math.max(0, deltaSeconds), this.blackboard);
        this.lastTrace.push(`update:${this.current.id}`);
        const transition = this.current.transitions.find((entry) => entry.condition(this.blackboard));
        if (transition) {
            this.transitionTo(transition);
        }
        return this.snapshot();
    }
    set(key, value) {
        this.blackboard.set(key, value);
    }
    snapshot() {
        return {
            running: this.running,
            currentState: this.current?.id ?? "none",
            previousState: this.previous?.id ?? "none",
            tickCount: this.tickCounter,
            transitionCount: this.transitionCounter,
            history: [...this.history],
            trace: [...this.lastTrace]
        };
    }
    transitionTo(transition) {
        if (!this.current)
            return;
        const from = this.current;
        const to = this.requireState(transition.targetState);
        from.onExit?.(this.blackboard);
        this.previous = from;
        this.current = to;
        this.transitionCounter += 1;
        this.history.push(`${from.id}->${to.id}`);
        while (this.history.length > this.maxHistorySize)
            this.history.shift();
        this.lastTrace.push(`transition:${transition.name}`);
        to.onEnter?.(this.blackboard);
        this.lastTrace.push(`enter:${to.id}`);
    }
    requireState(id) {
        const state = this.states.get(id);
        if (!state)
            throw new Error(`State is not registered: ${id}`);
        return state;
    }
}
//# sourceMappingURL=StateMachine.js.map