export type OutputHandler<T = unknown> = (payload: T) => void | Promise<void>;
export interface OutputHost extends HTMLElement {
  __wrnexusOutputHandlers?: Map<string, Set<OutputHandler>>;
}

export function registerOutputHandler<T>(
  host: OutputHost,
  name: string,
  handler: OutputHandler<T>,
): () => void {
  const registry = (host.__wrnexusOutputHandlers ??= new Map());
  const handlers = registry.get(name) ?? new Set();
  handlers.add(handler as OutputHandler);
  registry.set(name, handlers);
  return () => {
    handlers.delete(handler as OutputHandler);
    if (!handlers.size) registry.delete(name);
  };
}

export async function invokeOutput<T>(host: OutputHost, name: string, payload?: T): Promise<void> {
  const handlers = host.__wrnexusOutputHandlers?.get(name);
  if (handlers?.size) {
    for (const handler of handlers) await handler(payload);
    return;
  }
  // Compatibility path for legacy listeners outside a hydrated WRN parent.
  host.dispatchEvent(new CustomEvent(name, { detail: payload }));
  host.dispatchEvent(new CustomEvent(`wrnexus:${name}`, { detail: payload }));
}

export function createOutputProxy<T extends Record<string, (...args: any[]) => void>>(
  host: OutputHost,
): T {
  return new Proxy({} as T, {
    get: (_target, property) => (payload?: unknown) =>
      invokeOutput(host, String(property), payload),
  });
}
