/**
 * Request Context
 *
 * Carries "who is making this request" alongside the async call chain, so code
 * far from the route handler can attribute work to a person without every
 * intermediate function having to pass a userId down.
 *
 * This exists for one concrete reason: AI jobs are created from 136 call sites
 * across ~40 route files. Threading a userId through all of them to attribute a
 * completion notification would touch every AI route in the codebase for no
 * behavioural gain. The authenticated user is already on the request; this makes
 * it readable from wherever the job actually finishes.
 *
 * Read-only and best-effort by design — `getRequestContext()` returns undefined
 * outside a request (workers, cron, scripts) and callers must cope with that.
 * Nothing here may ever be used for authorisation: it is attribution only, and
 * every access check must keep using `req.user` and the existing middleware.
 */

import { AsyncLocalStorage } from 'async_hooks';
import type { Request, Response, NextFunction } from 'express';

export interface RequestContext {
  userId?: string;
  userName?: string;
  organizationId?: string | null;
}

const storage = new AsyncLocalStorage<RequestContext>();

/** The context for the request in flight, or undefined outside one. */
export function getRequestContext(): RequestContext | undefined {
  return storage.getStore();
}

/**
 * Populate the context for the rest of this request.
 *
 * Mounted after the routers' own `authenticate` middleware would have run is
 * NOT possible with a global mount, so this reads `req.user` lazily: the store
 * object is created up front and filled in by `captureAuthenticatedUser` once
 * authentication has happened.
 */
export function requestContextMiddleware(req: Request, _res: Response, next: NextFunction): void {
  const context: RequestContext = {};
  storage.run(context, () => {
    // Populated later by `captureAuthenticatedUser`, once a route's own
    // authenticate middleware has resolved the user.
    (req as any).__requestContext = context;
    next();
  });
}

/**
 * Copy the authenticated user into the active context.
 *
 * Called from the `authenticate` middleware, which is the first point at which
 * the user is known. Safe to call repeatedly and safe when no context exists.
 */
export function captureAuthenticatedUser(req: Request): void {
  const context = storage.getStore() || (req as any).__requestContext;
  if (!context) return;

  const user = req.user as any;
  if (!user) return;

  context.userId = String(user.id ?? user._id ?? '');
  context.userName = user.name;
  context.organizationId = user.activeCompanyId || user.companyIds?.[0] || null;
}
