import { AsyncLocalStorage } from 'async_hooks';
import { ActorType } from '@wms/shared';

/**
 * Per-request context propagated through AsyncLocalStorage so that services
 * deep in the call stack know the tenant, actor and request id without
 * threading them through every signature.
 */
export interface RequestContext {
  requestId: string;
  tenantId: string | null; // null for platform-admin requests
  actorType: ActorType;
  actorId: string | null;
  actorName: string | null;
  userId: string | null;
  /** user session id (from the access token); null for API keys and platform staff */
  sessionId?: string | null;
  storerId: string | null; // storer-scoped users / api keys
  permissions: string[];
  warehouseIds: string[] | 'ALL';
  features: string[];
  ip?: string;
  userAgent?: string;
  deviceId?: string;
  /** when true, DB access runs with RLS bypass (platform admin, system jobs) */
  bypassRls: boolean;
}

export const requestContextStorage = new AsyncLocalStorage<RequestContext>();

export function getRequestContext(): RequestContext | undefined {
  return requestContextStorage.getStore();
}

export function requireRequestContext(): RequestContext {
  const ctx = requestContextStorage.getStore();
  if (!ctx) throw new Error('No request context. Wrap the call in runWithContext().');
  return ctx;
}

export function runWithContext<T>(ctx: RequestContext, fn: () => Promise<T>): Promise<T> {
  return requestContextStorage.run(ctx, fn);
}

export function systemContext(tenantId: string | null, opts: Partial<RequestContext> = {}): RequestContext {
  return {
    requestId: opts.requestId ?? `sys-${Date.now()}`,
    tenantId,
    actorType: 'SYSTEM',
    actorId: 'system',
    actorName: 'system',
    userId: null,
    storerId: null,
    permissions: ['*'],
    warehouseIds: 'ALL',
    features: [],
    bypassRls: tenantId === null,
    ...opts,
  };
}
