"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
function _export(target, all) {
    for(var name in all)Object.defineProperty(target, name, {
        enumerable: true,
        get: all[name]
    });
}
_export(exports, {
    EventCaller: function() {
        return EventCaller;
    },
    getEventCaller: function() {
        return getEventCaller;
    },
    wrapEventCaller: function() {
        return wrapEventCaller;
    }
});
const _env = require("@llamaindex/env");
const _utils = require("../utils.js");
const eventReasonAsyncLocalStorage = new _env.AsyncLocalStorage();
class EventCaller {
    caller;
    parent;
    id;
    constructor(caller, parent){
        this.caller = caller;
        this.parent = parent;
        this.id = (0, _env.randomUUID)();
        this.#computedCallers = null;
    }
    #computedCallers;
    get computedCallers() {
        if (this.#computedCallers != null) {
            return this.#computedCallers;
        }
        const callers = [
            this.caller
        ];
        let parent = this.parent;
        while(parent != null){
            callers.push(parent.caller);
            parent = parent.parent;
        }
        this.#computedCallers = callers;
        return callers;
    }
    static create(caller, parent) {
        return new EventCaller(caller, parent);
    }
}
function getEventCaller() {
    return eventReasonAsyncLocalStorage.getStore() ?? null;
}
/**
 * @param caller who is calling this function, pass in `this` if it's a class method
 * @param fn
 */ function withEventCaller(caller, fn) {
    // create a chain of event callers
    const parentCaller = getEventCaller();
    return eventReasonAsyncLocalStorage.run(EventCaller.create(caller, parentCaller), fn);
}
function wrapEventCaller(originalMethod, context) {
    const name = context.name;
    context.addInitializer(function() {
        // @ts-expect-error
        const fn = this[name].bind(this);
        // @ts-expect-error
        this[name] = (...args)=>{
            return withEventCaller(this, ()=>fn(...args));
        };
    });
    return function(...args) {
        const result = originalMethod.call(this, ...args);
        // patch for iterators because AsyncLocalStorage doesn't work with them
        if ((0, _utils.isAsyncIterable)(result)) {
            const iter = result[Symbol.asyncIterator]();
            const snapshot = _env.AsyncLocalStorage.snapshot();
            return async function* asyncGeneratorWrapper() {
                while(true){
                    const { value, done } = await snapshot(()=>iter.next());
                    if (done) {
                        break;
                    }
                    yield value;
                }
            }();
        } else if ((0, _utils.isIterable)(result)) {
            const iter = result[Symbol.iterator]();
            const snapshot = _env.AsyncLocalStorage.snapshot();
            return function* generatorWrapper() {
                while(true){
                    const { value, done } = snapshot(()=>iter.next());
                    if (done) {
                        break;
                    }
                    yield value;
                }
            }();
        }
        return result;
    };
}
