import type { AiDriver } from '../components/ai-driver/ai-driver';

/**
 * Module-level registry of AI drivers keyed by session identity string.
 *
 * Driver lifetime is tied to the conversation session, not the DOM.
 * Components look up or create drivers on connect and only unwire
 * event listeners on disconnect — the driver is never destroyed by
 * a lifecycle event.
 *
 * @internal
 */
interface DriverRegistryEntry {
  driver: AiDriver;
  /**
   * Fingerprint (see `FoundationAiAssistant.getAgentsKey`) of the agents array
   * the driver was built for. Lets a second component sharing the same session
   * key recognise that the registry driver already matches its desired agents
   * and ADOPT it, instead of tearing it down and recreating — which would evict
   * the sibling's driver and orphan whichever element is mid-turn on it
   * (GENC-1388).
   */
  agentsKey: string;
}

const driverRegistry = new Map<string, DriverRegistryEntry>();

/**
 * Returns the existing driver for the given key, or calls the factory to create
 * and register a new one. `agentsKey` is the fingerprint of the agents the
 * driver is being built for; it is recorded only when a driver is created (a
 * reused driver keeps the fingerprint it was originally built with).
 */
export function getOrCreateDriver(
  key: string,
  agentsKey: string,
  factory: () => AiDriver,
): AiDriver {
  const existing = driverRegistry.get(key);
  if (existing) return existing.driver;
  const driver = factory();
  driverRegistry.set(key, { driver, agentsKey });
  return driver;
}

/**
 * Returns the existing driver for the given key, or `undefined`.
 */
export function getDriver(key: string): AiDriver | undefined {
  return driverRegistry.get(key)?.driver;
}

/**
 * The agents fingerprint the registry driver for `key` was built with, or
 * `undefined` if no driver is registered. Used by `agentsChanged` to decide
 * whether a sibling has already rebuilt the shared driver to the desired agents.
 */
export function getDriverAgentsKey(key: string): string | undefined {
  return driverRegistry.get(key)?.agentsKey;
}

/**
 * Removes and returns the driver for the given key.
 * Used when agents change (driver must be rebuilt) or on explicit session teardown.
 */
export function deleteDriver(key: string): AiDriver | undefined {
  const entry = driverRegistry.get(key);
  driverRegistry.delete(key);
  return entry?.driver;
}

/**
 * Removes all entries. Exposed for test isolation only — not part of the public API.
 *
 * @internal
 */
export function clearDriverRegistry(): void {
  driverRegistry.clear();
}
