/**
 * @file BehaviorTree.ts
 * @description Behavior Tree System with Graphical Editor Support
 * PRO-1.4: Professional Editor Features
 *
 * Features:
 * - Full behavior tree implementation
 * - Composite nodes (Selector, Sequence, Parallel)
 * - Decorator nodes (Inverter, Repeater, Succeeder, etc.)
 * - Leaf nodes (Actions, Conditions)
 * - Real-time preview and debugging
 * - Blackboard system for shared data
 * - Subtree support
 * - Serialization support
 */
/** Blackboard for sharing data between nodes */
class BTBlackboard {
    constructor() {
        this.data = new Map();
        this.types = new Map();
        this.listeners = new Map();
    }
    /** Set a value in the blackboard */
    set(key, value) {
        const name = typeof key === 'string' ? key : key.name;
        const oldValue = this.data.get(name);
        this.data.set(name, value);
        if (typeof key !== 'string') {
            this.types.set(name, key.type);
        }
        // Notify listeners
        if (oldValue !== value) {
            const callbacks = this.listeners.get(name);
            if (callbacks) {
                for (const cb of callbacks) {
                    cb(value);
                }
            }
        }
    }
    /** Get a value from the blackboard */
    get(key) {
        const name = typeof key === 'string' ? key : key.name;
        const value = this.data.get(name);
        if (value === undefined && typeof key !== 'string' && key.defaultValue !== undefined) {
            return key.defaultValue;
        }
        return value;
    }
    /** Check if key exists */
    has(key) {
        const name = typeof key === 'string' ? key : key.name;
        return this.data.has(name);
    }
    /** Remove a key */
    delete(key) {
        const name = typeof key === 'string' ? key : key.name;
        this.data.delete(name);
        this.types.delete(name);
    }
    /** Clear all data */
    clear() {
        this.data.clear();
    }
    /** Subscribe to key changes */
    subscribe(key, callback) {
        const name = typeof key === 'string' ? key : key.name;
        let callbacks = this.listeners.get(name);
        if (!callbacks) {
            callbacks = [];
            this.listeners.set(name, callbacks);
        }
        callbacks.push(callback);
        // Return unsubscribe function
        return () => {
            const idx = callbacks.indexOf(callback);
            if (idx >= 0) {
                callbacks.splice(idx, 1);
            }
        };
    }
    /** Get all keys */
    keys() {
        return Array.from(this.data.keys());
    }
    /** Clone the blackboard */
    clone() {
        const bb = new BTBlackboard();
        for (const [key, value] of this.data) {
            bb.data.set(key, value);
        }
        for (const [key, type] of this.types) {
            bb.types.set(key, type);
        }
        return bb;
    }
    /** Export to JSON */
    toJSON() {
        const result = {};
        for (const [key, value] of this.data) {
            result[key] = value;
        }
        return result;
    }
    /** Import from JSON */
    fromJSON(data) {
        for (const [key, value] of Object.entries(data)) {
            this.data.set(key, value);
        }
    }
}
/** Base class for all behavior tree nodes */
class BTNode {
    constructor(type, category, name) {
        /** Position in editor */
        this.position = { x: 0, y: 0 };
        /** Custom properties */
        this.properties = {};
        /** Current execution status (for debugging) */
        this.lastStatus = 'inactive';
        /** Last execution time (for profiling) */
        this.lastExecutionTime = 0;
        this.id = `bt_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
        this.type = type;
        this.category = category;
        this.name = name;
    }
    /** Initialize the node */
    initialize(context) { }
    /** Reset the node state */
    reset() {
        this.lastStatus = 'inactive';
    }
    /** Called when execution is aborted */
    abort() {
        this.lastStatus = 'aborted';
    }
    /** Serialize to JSON */
    toJSON() {
        return {
            id: this.id,
            type: this.type,
            category: this.category,
            name: this.name,
            position: this.position,
            properties: this.properties,
            comment: this.comment,
        };
    }
}
// ============================================================
// Composite Nodes
// ============================================================
/** Base class for composite nodes (have children) */
class BTComposite extends BTNode {
    constructor(type, name) {
        super(type, 'composite', name);
        this.children = [];
        this.currentChild = 0;
    }
    addChild(child) {
        this.children.push(child);
    }
    removeChild(child) {
        const idx = this.children.indexOf(child);
        if (idx >= 0) {
            this.children.splice(idx, 1);
        }
    }
    reset() {
        super.reset();
        this.currentChild = 0;
        for (const child of this.children) {
            child.reset();
        }
    }
    abort() {
        super.abort();
        // Abort currently running child
        if (this.currentChild < this.children.length) {
            this.children[this.currentChild].abort();
        }
    }
    toJSON() {
        return {
            ...super.toJSON(),
            children: this.children.map((c) => c.toJSON()),
        };
    }
}
/** Sequence: Runs children in order until one fails */
class BTSequence extends BTComposite {
    constructor(name = 'Sequence') {
        super('sequence', name);
    }
    tick(context) {
        while (this.currentChild < this.children.length) {
            const child = this.children[this.currentChild];
            const status = child.tick(context);
            child.lastStatus = status;
            if (status === 'running') {
                this.lastStatus = 'running';
                return 'running';
            }
            if (status === 'failure') {
                this.currentChild = 0;
                this.lastStatus = 'failure';
                return 'failure';
            }
            this.currentChild++;
        }
        this.currentChild = 0;
        this.lastStatus = 'success';
        return 'success';
    }
    clone() {
        const node = new BTSequence(this.name);
        node.properties = { ...this.properties };
        node.position = { ...this.position };
        node.children = this.children.map((c) => c.clone());
        return node;
    }
}
/** Selector: Runs children until one succeeds */
class BTSelector extends BTComposite {
    constructor(name = 'Selector') {
        super('selector', name);
    }
    tick(context) {
        while (this.currentChild < this.children.length) {
            const child = this.children[this.currentChild];
            const status = child.tick(context);
            child.lastStatus = status;
            if (status === 'running') {
                this.lastStatus = 'running';
                return 'running';
            }
            if (status === 'success') {
                this.currentChild = 0;
                this.lastStatus = 'success';
                return 'success';
            }
            this.currentChild++;
        }
        this.currentChild = 0;
        this.lastStatus = 'failure';
        return 'failure';
    }
    clone() {
        const node = new BTSelector(this.name);
        node.properties = { ...this.properties };
        node.position = { ...this.position };
        node.children = this.children.map((c) => c.clone());
        return node;
    }
}
/** Parallel: Runs all children simultaneously */
class BTParallel extends BTComposite {
    constructor(name = 'Parallel') {
        super('parallel', name);
        /** Policy for determining success */
        this.successPolicy = 'all';
        /** Policy for determining failure */
        this.failurePolicy = 'one';
        this.childStatuses = [];
    }
    initialize(context) {
        this.childStatuses = new Array(this.children.length).fill('running');
    }
    tick(context) {
        let successCount = 0;
        let failureCount = 0;
        let runningCount = 0;
        for (let i = 0; i < this.children.length; i++) {
            // Skip already completed children
            if (this.childStatuses[i] !== 'running') {
                if (this.childStatuses[i] === 'success')
                    successCount++;
                else if (this.childStatuses[i] === 'failure')
                    failureCount++;
                continue;
            }
            const child = this.children[i];
            const status = child.tick(context);
            child.lastStatus = status;
            this.childStatuses[i] = status;
            if (status === 'success')
                successCount++;
            else if (status === 'failure')
                failureCount++;
            else
                runningCount++;
        }
        // Check failure policy
        if (this.failurePolicy === 'one' && failureCount > 0) {
            this.reset();
            this.lastStatus = 'failure';
            return 'failure';
        }
        if (this.failurePolicy === 'all' && failureCount === this.children.length) {
            this.reset();
            this.lastStatus = 'failure';
            return 'failure';
        }
        // Check success policy
        if (this.successPolicy === 'one' && successCount > 0) {
            this.reset();
            this.lastStatus = 'success';
            return 'success';
        }
        if (this.successPolicy === 'all' && successCount === this.children.length) {
            this.reset();
            this.lastStatus = 'success';
            return 'success';
        }
        // Still running
        if (runningCount > 0) {
            this.lastStatus = 'running';
            return 'running';
        }
        // Mixed results, depends on policy
        this.reset();
        this.lastStatus = 'failure';
        return 'failure';
    }
    reset() {
        super.reset();
        this.childStatuses = [];
    }
    clone() {
        const node = new BTParallel(this.name);
        node.properties = { ...this.properties };
        node.position = { ...this.position };
        node.successPolicy = this.successPolicy;
        node.failurePolicy = this.failurePolicy;
        node.children = this.children.map((c) => c.clone());
        return node;
    }
}
/** Random Selector: Selects children in random order */
class BTRandomSelector extends BTComposite {
    constructor(name = 'Random Selector') {
        super('randomSelector', name);
        this.shuffledOrder = [];
    }
    initialize(context) {
        this.shuffle();
    }
    shuffle() {
        this.shuffledOrder = this.children.map((_, i) => i);
        for (let i = this.shuffledOrder.length - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * (i + 1));
            [this.shuffledOrder[i], this.shuffledOrder[j]] = [
                this.shuffledOrder[j],
                this.shuffledOrder[i],
            ];
        }
    }
    tick(context) {
        while (this.currentChild < this.shuffledOrder.length) {
            const childIdx = this.shuffledOrder[this.currentChild];
            const child = this.children[childIdx];
            const status = child.tick(context);
            child.lastStatus = status;
            if (status === 'running') {
                this.lastStatus = 'running';
                return 'running';
            }
            if (status === 'success') {
                this.currentChild = 0;
                this.shuffle();
                this.lastStatus = 'success';
                return 'success';
            }
            this.currentChild++;
        }
        this.currentChild = 0;
        this.shuffle();
        this.lastStatus = 'failure';
        return 'failure';
    }
    clone() {
        const node = new BTRandomSelector(this.name);
        node.properties = { ...this.properties };
        node.position = { ...this.position };
        node.children = this.children.map((c) => c.clone());
        return node;
    }
}
/** Random Sequence: Runs children in random order */
class BTRandomSequence extends BTComposite {
    constructor(name = 'Random Sequence') {
        super('randomSequence', name);
        this.shuffledOrder = [];
    }
    initialize(context) {
        this.shuffle();
    }
    shuffle() {
        this.shuffledOrder = this.children.map((_, i) => i);
        for (let i = this.shuffledOrder.length - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * (i + 1));
            [this.shuffledOrder[i], this.shuffledOrder[j]] = [
                this.shuffledOrder[j],
                this.shuffledOrder[i],
            ];
        }
    }
    tick(context) {
        while (this.currentChild < this.shuffledOrder.length) {
            const childIdx = this.shuffledOrder[this.currentChild];
            const child = this.children[childIdx];
            const status = child.tick(context);
            child.lastStatus = status;
            if (status === 'running') {
                this.lastStatus = 'running';
                return 'running';
            }
            if (status === 'failure') {
                this.currentChild = 0;
                this.shuffle();
                this.lastStatus = 'failure';
                return 'failure';
            }
            this.currentChild++;
        }
        this.currentChild = 0;
        this.shuffle();
        this.lastStatus = 'success';
        return 'success';
    }
    clone() {
        const node = new BTRandomSequence(this.name);
        node.properties = { ...this.properties };
        node.position = { ...this.position };
        node.children = this.children.map((c) => c.clone());
        return node;
    }
}
// ============================================================
// Decorator Nodes
// ============================================================
/** Base class for decorator nodes (single child) */
class BTDecorator extends BTNode {
    constructor(type, name) {
        super(type, 'decorator', name);
        this.child = null;
    }
    setChild(child) {
        this.child = child;
    }
    reset() {
        var _a;
        super.reset();
        (_a = this.child) === null || _a === void 0 ? void 0 : _a.reset();
    }
    abort() {
        var _a;
        super.abort();
        (_a = this.child) === null || _a === void 0 ? void 0 : _a.abort();
    }
    toJSON() {
        return {
            ...super.toJSON(),
            children: this.child ? [this.child.toJSON()] : [],
        };
    }
}
/** Inverter: Inverts child's result */
class BTInverter extends BTDecorator {
    constructor(name = 'Inverter') {
        super('inverter', name);
    }
    tick(context) {
        if (!this.child) {
            this.lastStatus = 'failure';
            return 'failure';
        }
        const status = this.child.tick(context);
        this.child.lastStatus = status;
        if (status === 'running') {
            this.lastStatus = 'running';
            return 'running';
        }
        const inverted = status === 'success' ? 'failure' : 'success';
        this.lastStatus = inverted;
        return inverted;
    }
    clone() {
        var _a;
        const node = new BTInverter(this.name);
        node.properties = { ...this.properties };
        node.position = { ...this.position };
        node.child = ((_a = this.child) === null || _a === void 0 ? void 0 : _a.clone()) || null;
        return node;
    }
}
/** Succeeder: Always returns success */
class BTSucceeder extends BTDecorator {
    constructor(name = 'Succeeder') {
        super('succeeder', name);
    }
    tick(context) {
        if (!this.child) {
            this.lastStatus = 'success';
            return 'success';
        }
        const status = this.child.tick(context);
        this.child.lastStatus = status;
        if (status === 'running') {
            this.lastStatus = 'running';
            return 'running';
        }
        this.lastStatus = 'success';
        return 'success';
    }
    clone() {
        var _a;
        const node = new BTSucceeder(this.name);
        node.properties = { ...this.properties };
        node.position = { ...this.position };
        node.child = ((_a = this.child) === null || _a === void 0 ? void 0 : _a.clone()) || null;
        return node;
    }
}
/** Failer: Always returns failure */
class BTFailer extends BTDecorator {
    constructor(name = 'Failer') {
        super('failer', name);
    }
    tick(context) {
        if (!this.child) {
            this.lastStatus = 'failure';
            return 'failure';
        }
        const status = this.child.tick(context);
        this.child.lastStatus = status;
        if (status === 'running') {
            this.lastStatus = 'running';
            return 'running';
        }
        this.lastStatus = 'failure';
        return 'failure';
    }
    clone() {
        var _a;
        const node = new BTFailer(this.name);
        node.properties = { ...this.properties };
        node.position = { ...this.position };
        node.child = ((_a = this.child) === null || _a === void 0 ? void 0 : _a.clone()) || null;
        return node;
    }
}
/** Repeater: Repeats child N times */
class BTRepeater extends BTDecorator {
    constructor(name = 'Repeater', times = -1) {
        super('repeater', name);
        this.times = -1; // -1 = infinite
        this.currentCount = 0;
        this.times = times;
    }
    tick(context) {
        if (!this.child) {
            this.lastStatus = 'failure';
            return 'failure';
        }
        while (this.times === -1 || this.currentCount < this.times) {
            const status = this.child.tick(context);
            this.child.lastStatus = status;
            if (status === 'running') {
                this.lastStatus = 'running';
                return 'running';
            }
            this.currentCount++;
            this.child.reset();
        }
        this.currentCount = 0;
        this.lastStatus = 'success';
        return 'success';
    }
    reset() {
        super.reset();
        this.currentCount = 0;
    }
    clone() {
        var _a;
        const node = new BTRepeater(this.name, this.times);
        node.properties = { ...this.properties };
        node.position = { ...this.position };
        node.child = ((_a = this.child) === null || _a === void 0 ? void 0 : _a.clone()) || null;
        return node;
    }
}
/** RepeatUntilFail: Repeats until child fails */
class BTRepeatUntilFail extends BTDecorator {
    constructor(name = 'Repeat Until Fail') {
        super('repeatUntilFail', name);
    }
    tick(context) {
        if (!this.child) {
            this.lastStatus = 'failure';
            return 'failure';
        }
        const status = this.child.tick(context);
        this.child.lastStatus = status;
        if (status === 'failure') {
            this.lastStatus = 'success';
            return 'success';
        }
        if (status === 'running') {
            this.lastStatus = 'running';
            return 'running';
        }
        // Success - reset and continue
        this.child.reset();
        this.lastStatus = 'running';
        return 'running';
    }
    clone() {
        var _a;
        const node = new BTRepeatUntilFail(this.name);
        node.properties = { ...this.properties };
        node.position = { ...this.position };
        node.child = ((_a = this.child) === null || _a === void 0 ? void 0 : _a.clone()) || null;
        return node;
    }
}
/** RepeatUntilSuccess: Repeats until child succeeds */
class BTRepeatUntilSuccess extends BTDecorator {
    constructor(name = 'Repeat Until Success') {
        super('repeatUntilSuccess', name);
    }
    tick(context) {
        if (!this.child) {
            this.lastStatus = 'failure';
            return 'failure';
        }
        const status = this.child.tick(context);
        this.child.lastStatus = status;
        if (status === 'success') {
            this.lastStatus = 'success';
            return 'success';
        }
        if (status === 'running') {
            this.lastStatus = 'running';
            return 'running';
        }
        // Failure - reset and continue
        this.child.reset();
        this.lastStatus = 'running';
        return 'running';
    }
    clone() {
        var _a;
        const node = new BTRepeatUntilSuccess(this.name);
        node.properties = { ...this.properties };
        node.position = { ...this.position };
        node.child = ((_a = this.child) === null || _a === void 0 ? void 0 : _a.clone()) || null;
        return node;
    }
}
/** Timeout: Fails if child takes too long */
class BTTimeout extends BTDecorator {
    constructor(name = 'Timeout', seconds = 5) {
        super('timeout', name);
        this.elapsed = 0;
        this.started = false;
        this.timeoutSeconds = seconds;
    }
    tick(context) {
        if (!this.child) {
            this.lastStatus = 'failure';
            return 'failure';
        }
        if (!this.started) {
            this.elapsed = 0;
            this.started = true;
        }
        this.elapsed += context.dt;
        if (this.elapsed >= this.timeoutSeconds) {
            this.child.abort();
            this.started = false;
            this.lastStatus = 'failure';
            return 'failure';
        }
        const status = this.child.tick(context);
        this.child.lastStatus = status;
        if (status !== 'running') {
            this.started = false;
        }
        this.lastStatus = status;
        return status;
    }
    reset() {
        super.reset();
        this.elapsed = 0;
        this.started = false;
    }
    clone() {
        var _a;
        const node = new BTTimeout(this.name, this.timeoutSeconds);
        node.properties = { ...this.properties };
        node.position = { ...this.position };
        node.child = ((_a = this.child) === null || _a === void 0 ? void 0 : _a.clone()) || null;
        return node;
    }
}
/** Cooldown: Rate limits child execution */
class BTCooldown extends BTDecorator {
    constructor(name = 'Cooldown', seconds = 1) {
        super('cooldown', name);
        this.lastExecution = -Infinity;
        this.cooldownSeconds = seconds;
    }
    tick(context) {
        if (!this.child) {
            this.lastStatus = 'failure';
            return 'failure';
        }
        const elapsed = context.time - this.lastExecution;
        if (elapsed < this.cooldownSeconds) {
            this.lastStatus = 'failure';
            return 'failure';
        }
        const status = this.child.tick(context);
        this.child.lastStatus = status;
        if (status !== 'running') {
            this.lastExecution = context.time;
        }
        this.lastStatus = status;
        return status;
    }
    reset() {
        super.reset();
        // Don't reset lastExecution - cooldown should persist
    }
    clone() {
        var _a;
        const node = new BTCooldown(this.name, this.cooldownSeconds);
        node.properties = { ...this.properties };
        node.position = { ...this.position };
        node.child = ((_a = this.child) === null || _a === void 0 ? void 0 : _a.clone()) || null;
        return node;
    }
}
/** Condition Guard: Only runs child if condition is true */
class BTConditionGuard extends BTDecorator {
    constructor(name = 'Guard', condition = () => true) {
        super('guard', name);
        this.condition = condition;
    }
    tick(context) {
        if (!this.child) {
            this.lastStatus = 'failure';
            return 'failure';
        }
        if (!this.condition(context)) {
            this.lastStatus = 'failure';
            return 'failure';
        }
        const status = this.child.tick(context);
        this.child.lastStatus = status;
        this.lastStatus = status;
        return status;
    }
    clone() {
        var _a;
        const node = new BTConditionGuard(this.name, this.condition);
        node.properties = { ...this.properties };
        node.position = { ...this.position };
        node.child = ((_a = this.child) === null || _a === void 0 ? void 0 : _a.clone()) || null;
        return node;
    }
}
/** Wait Action: Waits for a duration */
class BTWait extends BTNode {
    constructor(name = 'Wait', seconds = 1) {
        super('wait', 'action', name);
        this.elapsed = 0;
        this.started = false;
        this.seconds = seconds;
    }
    tick(context) {
        if (!this.started) {
            this.elapsed = 0;
            this.started = true;
        }
        this.elapsed += context.dt;
        if (this.elapsed >= this.seconds) {
            this.started = false;
            this.lastStatus = 'success';
            return 'success';
        }
        this.lastStatus = 'running';
        return 'running';
    }
    reset() {
        super.reset();
        this.elapsed = 0;
        this.started = false;
    }
    clone() {
        const node = new BTWait(this.name, this.seconds);
        node.properties = { ...this.properties };
        node.position = { ...this.position };
        return node;
    }
}
/** Log Action: Logs a message */
class BTLog extends BTNode {
    constructor(name = 'Log', message = '', level = 'info') {
        super('log', 'action', name);
        this.message = message;
        this.level = level;
    }
    tick(context) {
        console.log(`[BT ${this.level}] ${this.message}`);
        this.lastStatus = 'success';
        return 'success';
    }
    clone() {
        const node = new BTLog(this.name, this.message, this.level);
        node.properties = { ...this.properties };
        node.position = { ...this.position };
        return node;
    }
}
// ============================================================
// Subtree Node
// ============================================================
class BTSubtree extends BTNode {
    constructor(name, subtreeId) {
        super('subtree', 'subtree', name);
        this.subtree = null;
        this.subtreeId = subtreeId;
    }
    setSubtree(tree) {
        this.subtree = tree;
    }
    tick(context) {
        if (!this.subtree) {
            this.lastStatus = 'failure';
            return 'failure';
        }
        const status = this.subtree.tick(context);
        this.lastStatus = status;
        return status;
    }
    reset() {
        var _a;
        super.reset();
        (_a = this.subtree) === null || _a === void 0 ? void 0 : _a.reset();
    }
    clone() {
        var _a;
        const node = new BTSubtree(this.name, this.subtreeId);
        node.properties = { ...this.properties };
        node.position = { ...this.position };
        node.subtree = ((_a = this.subtree) === null || _a === void 0 ? void 0 : _a.clone()) || null;
        return node;
    }
}
// ============================================================
// Root Node
// ============================================================
class BTRoot extends BTNode {
    constructor(name = 'Root') {
        super('root', 'root', name);
        this.child = null;
    }
    setChild(child) {
        this.child = child;
    }
    tick(context) {
        if (!this.child) {
            this.lastStatus = 'success';
            return 'success';
        }
        const status = this.child.tick(context);
        this.child.lastStatus = status;
        this.lastStatus = status;
        return status;
    }
    reset() {
        var _a;
        super.reset();
        (_a = this.child) === null || _a === void 0 ? void 0 : _a.reset();
    }
    toJSON() {
        return {
            ...super.toJSON(),
            children: this.child ? [this.child.toJSON()] : [],
        };
    }
    clone() {
        var _a;
        const node = new BTRoot(this.name);
        node.properties = { ...this.properties };
        node.position = { ...this.position };
        node.child = ((_a = this.child) === null || _a === void 0 ? void 0 : _a.clone()) || null;
        return node;
    }
}
// ============================================================
// Behavior Tree
// ============================================================
class BehaviorTree {
    constructor(name = 'Behavior Tree') {
        /** Execution statistics */
        this.stats = {
            tickCount: 0,
            lastTickTime: 0,
            averageTickTime: 0,
        };
        /** Debugging */
        this.debugMode = false;
        this.breakpoints = new Set();
        this.isPaused = false;
        this.id = `tree_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
        this.name = name;
        this.root = new BTRoot();
        this.blackboard = new BTBlackboard();
    }
    /** Tick the tree */
    tick(context) {
        if (this.isPaused) {
            return 'running';
        }
        // Merge blackboards
        const mergedContext = {
            ...context,
            blackboard: this.blackboard,
        };
        const startTime = performance.now();
        const status = this.root.tick(mergedContext);
        const endTime = performance.now();
        // Update stats
        this.stats.tickCount++;
        this.stats.lastTickTime = endTime - startTime;
        this.stats.averageTickTime =
            (this.stats.averageTickTime * (this.stats.tickCount - 1) + this.stats.lastTickTime) /
                this.stats.tickCount;
        return status;
    }
    /** Reset the tree */
    reset() {
        this.root.reset();
    }
    /** Pause execution */
    pause() {
        this.isPaused = true;
    }
    /** Resume execution */
    resume() {
        this.isPaused = false;
    }
    /** Add breakpoint */
    addBreakpoint(nodeId) {
        this.breakpoints.add(nodeId);
    }
    /** Remove breakpoint */
    removeBreakpoint(nodeId) {
        this.breakpoints.delete(nodeId);
    }
    /** Toggle breakpoint */
    toggleBreakpoint(nodeId) {
        if (this.breakpoints.has(nodeId)) {
            this.breakpoints.delete(nodeId);
        }
        else {
            this.breakpoints.add(nodeId);
        }
    }
    /** Find node by ID */
    findNode(nodeId) {
        return this.findNodeRecursive(this.root, nodeId);
    }
    findNodeRecursive(node, nodeId) {
        if (node.id === nodeId)
            return node;
        if (node instanceof BTComposite) {
            for (const child of node.children) {
                const found = this.findNodeRecursive(child, nodeId);
                if (found)
                    return found;
            }
        }
        else if (node instanceof BTDecorator && node.child) {
            return this.findNodeRecursive(node.child, nodeId);
        }
        else if (node instanceof BTRoot && node.child) {
            return this.findNodeRecursive(node.child, nodeId);
        }
        return null;
    }
    /** Get all nodes */
    getAllNodes() {
        const nodes = [];
        this.collectNodes(this.root, nodes);
        return nodes;
    }
    collectNodes(node, nodes) {
        nodes.push(node);
        if (node instanceof BTComposite) {
            for (const child of node.children) {
                this.collectNodes(child, nodes);
            }
        }
        else if (node instanceof BTDecorator && node.child) {
            this.collectNodes(node.child, nodes);
        }
        else if (node instanceof BTRoot && node.child) {
            this.collectNodes(node.child, nodes);
        }
    }
    /** Clone the tree */
    clone() {
        const tree = new BehaviorTree(this.name);
        tree.root = this.root.clone();
        tree.blackboard = this.blackboard.clone();
        return tree;
    }
    /** Serialize to JSON */
    toJSON() {
        return {
            id: this.id,
            name: this.name,
            root: this.root.toJSON(),
            blackboard: this.blackboard.toJSON(),
        };
    }
}
// ============================================================
// Node Registry
// ============================================================
class BTNodeRegistry {
    constructor() {
        this.definitions = new Map();
    }
    register(definition) {
        this.definitions.set(definition.type, definition);
    }
    get(type) {
        return this.definitions.get(type);
    }
    getAll() {
        return Array.from(this.definitions.values());
    }
    getByCategory(category) {
        return this.getAll().filter((d) => d.category === category);
    }
    createNode(type, properties) {
        const def = this.definitions.get(type);
        if (!def)
            return null;
        return def.create(properties);
    }
}
// ============================================================
// Factory Functions
// ============================================================
function createBehaviorTree(name) {
    return new BehaviorTree(name);
}
function createBlackboard() {
    return new BTBlackboard();
}
function createNodeRegistry() {
    const registry = new BTNodeRegistry();
    // Register built-in nodes
    registry.register({
        type: 'sequence',
        category: 'composite',
        name: 'Sequence',
        description: 'Executes children in order until one fails',
        icon: 'arrow-right',
        color: '#3b82f6',
        create: () => new BTSequence(),
    });
    registry.register({
        type: 'selector',
        category: 'composite',
        name: 'Selector',
        description: 'Executes children until one succeeds',
        icon: 'git-branch',
        color: '#22c55e',
        create: () => new BTSelector(),
    });
    registry.register({
        type: 'parallel',
        category: 'composite',
        name: 'Parallel',
        description: 'Executes all children simultaneously',
        icon: 'layers',
        color: '#8b5cf6',
        properties: [
            { name: 'successPolicy', type: 'enum', enumValues: ['all', 'one'], default: 'all' },
            { name: 'failurePolicy', type: 'enum', enumValues: ['all', 'one'], default: 'one' },
        ],
        create: (props) => {
            const node = new BTParallel();
            if (props === null || props === void 0 ? void 0 : props.successPolicy)
                node.successPolicy = props.successPolicy;
            if (props === null || props === void 0 ? void 0 : props.failurePolicy)
                node.failurePolicy = props.failurePolicy;
            return node;
        },
    });
    registry.register({
        type: 'inverter',
        category: 'decorator',
        name: 'Inverter',
        description: 'Inverts the result of its child',
        icon: 'refresh-cw',
        color: '#f97316',
        create: () => new BTInverter(),
    });
    registry.register({
        type: 'repeater',
        category: 'decorator',
        name: 'Repeater',
        description: 'Repeats child N times (-1 = infinite)',
        icon: 'repeat',
        color: '#f97316',
        properties: [{ name: 'times', type: 'number', default: -1, min: -1 }],
        create: (props) => { var _a; return new BTRepeater('Repeater', (_a = props === null || props === void 0 ? void 0 : props.times) !== null && _a !== void 0 ? _a : -1); },
    });
    registry.register({
        type: 'timeout',
        category: 'decorator',
        name: 'Timeout',
        description: 'Fails if child takes too long',
        icon: 'clock',
        color: '#f97316',
        properties: [{ name: 'seconds', type: 'number', default: 5, min: 0 }],
        create: (props) => { var _a; return new BTTimeout('Timeout', (_a = props === null || props === void 0 ? void 0 : props.seconds) !== null && _a !== void 0 ? _a : 5); },
    });
    registry.register({
        type: 'wait',
        category: 'action',
        name: 'Wait',
        description: 'Waits for a duration',
        icon: 'pause',
        color: '#6b7280',
        properties: [{ name: 'seconds', type: 'number', default: 1, min: 0 }],
        create: (props) => { var _a; return new BTWait('Wait', (_a = props === null || props === void 0 ? void 0 : props.seconds) !== null && _a !== void 0 ? _a : 1); },
    });
    registry.register({
        type: 'log',
        category: 'action',
        name: 'Log',
        description: 'Logs a message',
        icon: 'message-square',
        color: '#6b7280',
        properties: [
            { name: 'message', type: 'string', default: '' },
            { name: 'level', type: 'enum', enumValues: ['info', 'warn', 'error'], default: 'info' },
        ],
        create: (props) => {
            var _a, _b;
            return new BTLog('Log', (_a = props === null || props === void 0 ? void 0 : props.message) !== null && _a !== void 0 ? _a : '', (_b = props === null || props === void 0 ? void 0 : props.level) !== null && _b !== void 0 ? _b : 'info');
        },
    });
    return registry;
}
/** Create execution context */
function createBTContext(params) {
    let isAborted = false;
    return {
        entityId: params.entityId,
        blackboard: params.blackboard || new BTBlackboard(),
        dt: params.dt,
        time: params.time,
        world: params.world,
        emit: () => { },
        abort: () => {
            isAborted = true;
        },
        get isAborted() {
            return isAborted;
        },
    };
}

export { BTBlackboard, BTComposite, BTConditionGuard, BTCooldown, BTDecorator, BTFailer, BTInverter, BTLog, BTNode, BTNodeRegistry, BTParallel, BTRandomSelector, BTRandomSequence, BTRepeatUntilFail, BTRepeatUntilSuccess, BTRepeater, BTRoot, BTSelector, BTSequence, BTSubtree, BTSucceeder, BTTimeout, BTWait, BehaviorTree, createBTContext, createBehaviorTree, createBlackboard, createNodeRegistry };
//# sourceMappingURL=BehaviorTree.js.map
