import { AsyncLocalStorage } from 'node:async_hooks';
import { StructuredError, } from '@agentuity/core';
import { AGENT_RUNTIME, CURRENT_AGENT } from './_config';
import { registerServices } from './_services';
export class RequestAgentContext {
    agent;
    logger;
    sessionId;
    tracer;
    kv;
    stream;
    vector;
    sandbox;
    queue;
    email;
    schedule;
    task;
    state;
    session;
    thread;
    config;
    app;
    current;
    [AGENT_RUNTIME];
    handler;
    /**
     * Fallback auth value for non-HTTP contexts (standalone, tests, etc.)
     * @internal
     */
    _initialAuth;
    /**
     * Authentication context - lazily reads from HTTP context if available.
     *
     * This is a getter that prefers the current HTTP context's `c.var.auth`,
     * allowing auth middleware that runs after the agent middleware to still
     * propagate auth to agents.
     */
    get auth() {
        // Prefer HTTP context var.auth if available (allows late-binding from route middleware)
        if (inHTTPContext()) {
            try {
                // eslint-disable-next-line @typescript-eslint/no-explicit-any
                const httpCtx = httpAsyncLocalStorage.getStore();
                if (httpCtx?.var && 'auth' in httpCtx.var) {
                    return httpCtx.var.auth ?? null;
                }
            }
            catch {
                // If HTTP context not available, fall through
            }
        }
        // Fallback: whatever was passed in at creation time (for standalone/test contexts)
        return this._initialAuth;
    }
    /**
     * Set auth for non-HTTP contexts (standalone, tests).
     * @internal
     */
    set auth(value) {
        this._initialAuth = value;
    }
    constructor(args) {
        this.agent = args.agent;
        this.logger = args.logger;
        this.sessionId = args.sessionId;
        this.tracer = args.tracer;
        this.thread = args.thread;
        this.session = args.session;
        this.config = args.config;
        this.app = args.app;
        this._initialAuth = args.auth ?? null;
        this[AGENT_RUNTIME] = args.runtime;
        this.state = new Map();
        this.handler = args.handler;
        registerServices(this, false); // agents already populated via args.agent
    }
    waitUntil(callback) {
        this.handler.waitUntil(callback);
    }
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const agentAsyncLocalStorage = new AsyncLocalStorage();
const httpAsyncLocalStorage = new AsyncLocalStorage();
export const inAgentContext = () => {
    const context = agentAsyncLocalStorage.getStore();
    return !!context;
};
export const inHTTPContext = () => {
    const context = httpAsyncLocalStorage.getStore();
    return !!context;
};
const AgentContextNotAvailableError = StructuredError('AgentContextNotAvailableError', 'AgentContext is not available');
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const getAgentContext = () => {
    const context = agentAsyncLocalStorage.getStore();
    if (!context) {
        throw new AgentContextNotAvailableError();
    }
    return context;
};
const HTTPContextNotAvailableError = StructuredError('HTTPContextNotAvailableError', 'HTTPContext is not available');
export const getHTTPContext = () => {
    const context = httpAsyncLocalStorage.getStore();
    if (!context) {
        throw new HTTPContextNotAvailableError();
    }
    return context;
};
export const getAgentAsyncLocalStorage = () => agentAsyncLocalStorage;
export const getHTTPAsyncLocalStorage = () => httpAsyncLocalStorage;
/**
 * Get the current executing agent's metadata (for internal telemetry use only).
 * Returns undefined if not in an agent context or no agent is executing.
 * @internal
 */
export const getCurrentAgentMetadata = () => {
    const context = agentAsyncLocalStorage.getStore();
    if (!context)
        return undefined;
    // Access internal symbol property
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    return context[CURRENT_AGENT]?.metadata;
};
export const setupRequestAgentContext = (ctxObject, args, next) => {
    const ctx = new RequestAgentContext(args);
    // Note: All Hono context variables are set via c.set() in _server.ts middleware.
    // RequestAgentContext is only used within agents via AsyncLocalStorage.
    // No properties need to be copied between them.
    // Provide c.waitUntil() directly on route context for consistency with AgentContext
    if (!('waitUntil' in ctxObject)) {
        Object.defineProperty(ctxObject, 'waitUntil', {
            value: (callback) => {
                args.handler.waitUntil(callback);
            },
            configurable: true,
        });
    }
    // Provide executionCtx.waitUntil for compatibility with Cloudflare Workers API
    Object.defineProperty(ctxObject, 'executionCtx', {
        get() {
            return {
                waitUntil: (promise) => {
                    args.handler.waitUntil(promise);
                },
                passThroughOnException: () => { },
                props: {},
            };
        },
        configurable: true,
    });
    return agentAsyncLocalStorage.run(ctx, async () => {
        const result = await next();
        return result;
    });
};
export const runInHTTPContext = async (ctx, next) => {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    return httpAsyncLocalStorage.run(ctx, next);
};
//# sourceMappingURL=_context.js.map