/**
 * AsyncLocalStorage-based context management for HTTP requests
 *
 * This module provides a way to pass HTTP request context (Hono Context)
 * through async call chains without explicit parameter passing.
 *
 * This is particularly useful for:
 * - Passing authentication info from middleware to tool callbacks
 * - Accessing request headers, user data, etc. in deeply nested functions
 * - Maintaining request isolation in concurrent request handling
 */

import { AsyncLocalStorage } from "node:async_hooks";
import type { Context } from "hono";

/**
 * Request context data stored in AsyncLocalStorage
 */
interface RequestContextData {
  honoContext: Context;
  sessionId?: string;
}

/**
 * Singleton AsyncLocalStorage instance for storing request context.
 *
 * Uses `globalThis` to guarantee a single instance even when bundlers
 * (tsup/esbuild) split this module into multiple chunks — dynamic imports
 * from resources/, prompts/, and proxy handlers would otherwise get a
 * different `AsyncLocalStorage` instance, causing `getRequestContext()`
 * to return `undefined` in tool handlers.
 */
const STORAGE_KEY = "__mcp_use_request_context_storage__";

const requestContextStorage: AsyncLocalStorage<RequestContextData> =
  (globalThis as any)[STORAGE_KEY] ??
  ((globalThis as any)[STORAGE_KEY] =
    new AsyncLocalStorage<RequestContextData>());

/**
 * Execute a function with a request context stored in AsyncLocalStorage
 *
 * @param context - Hono Context object to store
 * @param fn - Function to execute within this context
 * @param sessionId - Optional session ID to store with the context
 * @returns Promise resolving to the function's return value
 *
 * @example
 * ```typescript
 * app.post('/mcp', async (c) => {
 *   return runWithContext(c, async () => {
 *     // Any async operations here can access context via getRequestContext()
 *     await handleMcpRequest();
 *     return c.json({ success: true });
 *   });
 * });
 * ```
 */
export async function runWithContext<T>(
  context: Context,
  fn: () => Promise<T>,
  sessionId?: string
): Promise<T> {
  return requestContextStorage.run({ honoContext: context, sessionId }, fn);
}

/**
 * Get the current request context from AsyncLocalStorage
 *
 * @returns The Hono Context for the current async operation, or undefined if not in a request context
 *
 * @example
 * ```typescript
 * // Inside a tool callback
 * const context = getRequestContext();
 * if (context) {
 *   const user = context.get('user');
 *   console.log('Current user:', user);
 * }
 * ```
 */
export function getRequestContext(): Context | undefined {
  return requestContextStorage.getStore()?.honoContext;
}

/**
 * Get the current session ID from AsyncLocalStorage
 *
 * @returns The session ID for the current async operation, or undefined if not in a request context
 */
export function getSessionId(): string | undefined {
  return requestContextStorage.getStore()?.sessionId;
}

/**
 * Check if currently executing within a request context
 *
 * @returns true if a request context is available
 */
export function hasRequestContext(): boolean {
  return requestContextStorage.getStore() !== undefined;
}
