/**
 * Connector registry (F4 Phase 1).
 *
 * A tiny extensible registry so connector implementations (Phase 2: tmux,
 * Discord, Matrix) register a factory by kind and fleet core resolves one from
 * roster config without branching on kind. Phase 1 ships the registry + the
 * config→kind resolution; the connector factories land in Phase 2.
 */

import {
  type ConnectorConfig,
  type ConnectorKind,
  type OrchestratorConnector,
  DEFAULT_CONNECTOR_KIND,
} from './types.js';

/** The set of connector kinds the framework recognizes. */
export const KNOWN_CONNECTOR_KINDS: readonly ConnectorKind[] = ['tmux', 'discord', 'matrix'];

/** Type guard: is `value` a known connector kind? */
export function isKnownConnectorKind(value: unknown): value is ConnectorKind {
  return typeof value === 'string' && (KNOWN_CONNECTOR_KINDS as readonly string[]).includes(value);
}

/**
 * Resolve the connector kind from roster config. Absent config ⇒ the default
 * (tmux) so existing rosters keep working unchanged (back-compat).
 */
export function resolveConnectorKind(config?: ConnectorConfig): ConnectorKind {
  return config?.kind ?? DEFAULT_CONNECTOR_KIND;
}

/** A factory builds a live connector from its validated config. */
export type ConnectorFactory = (config: ConnectorConfig) => OrchestratorConnector;

/** Thrown when no factory is registered for a requested kind. */
export class ConnectorNotImplementedError extends Error {
  constructor(public readonly kind: ConnectorKind) {
    super(
      `Connector "${kind}" is not implemented yet. ` +
        `Register a factory via registerConnector('${kind}', …) (F4 Phase 2).`,
    );
    this.name = 'ConnectorNotImplementedError';
  }
}

const registry = new Map<ConnectorKind, ConnectorFactory>();

/** Register a connector factory for a kind (idempotent — last registration wins). */
export function registerConnector(kind: ConnectorKind, factory: ConnectorFactory): void {
  registry.set(kind, factory);
}

/** True when a factory is registered for `kind`. */
export function hasConnector(kind: ConnectorKind): boolean {
  return registry.has(kind);
}

/**
 * Build a connector from roster config. Throws `ConnectorNotImplementedError`
 * when no factory is registered for the resolved kind (the Phase-1 default for
 * every kind until Phase 2 registers them).
 */
export function createConnector(config?: ConnectorConfig): OrchestratorConnector {
  const kind = resolveConnectorKind(config);
  const factory = registry.get(kind);
  if (!factory) {
    throw new ConnectorNotImplementedError(kind);
  }
  return factory(config ?? { kind });
}

/** Test/runtime helper: drop all registrations. */
export function _resetConnectorRegistry(): void {
  registry.clear();
}
