import { describe, it, expect, beforeEach } from 'vitest';
import {
  KNOWN_CONNECTOR_KINDS,
  isKnownConnectorKind,
  resolveConnectorKind,
  registerConnector,
  hasConnector,
  createConnector,
  ConnectorNotImplementedError,
  _resetConnectorRegistry,
} from './registry.js';
import type { ConnectorConfig, OrchestratorConnector } from './types.js';

function fakeConnector(kind: 'tmux' | 'discord' | 'matrix'): OrchestratorConnector {
  return {
    kind,
    send: async () => ({ delivered: true, messageId: 'x' }),
    subscribe: () => () => {},
    health: async () => ({ reachable: true, authenticated: true }),
  };
}

describe('connector registry (F4 Phase 1)', () => {
  beforeEach(() => {
    _resetConnectorRegistry();
  });

  it('knows the three peer connector kinds', () => {
    expect(KNOWN_CONNECTOR_KINDS).toEqual(['tmux', 'discord', 'matrix']);
  });

  it('isKnownConnectorKind guards correctly', () => {
    expect(isKnownConnectorKind('matrix')).toBe(true);
    expect(isKnownConnectorKind('irc')).toBe(false);
    expect(isKnownConnectorKind(42)).toBe(false);
  });

  it('resolveConnectorKind defaults to tmux when config is absent (back-compat)', () => {
    expect(resolveConnectorKind(undefined)).toBe('tmux');
    expect(resolveConnectorKind({ kind: 'matrix' })).toBe('matrix');
  });

  it('createConnector throws ConnectorNotImplementedError for an unregistered kind', () => {
    const cfg: ConnectorConfig = { kind: 'matrix' };
    expect(() => createConnector(cfg)).toThrow(ConnectorNotImplementedError);
    expect(() => createConnector(cfg)).toThrow(/not implemented yet/i);
  });

  it('createConnector with no config resolves the default kind (tmux) and reports it unimplemented in Phase 1', () => {
    try {
      createConnector();
      throw new Error('expected throw');
    } catch (err) {
      expect(err).toBeInstanceOf(ConnectorNotImplementedError);
      expect((err as ConnectorNotImplementedError).kind).toBe('tmux');
    }
  });

  it('register → has → create resolves a registered factory', () => {
    expect(hasConnector('matrix')).toBe(false);
    registerConnector('matrix', (cfg) => fakeConnector(cfg.kind));
    expect(hasConnector('matrix')).toBe(true);

    const connector = createConnector({ kind: 'matrix' });
    expect(connector.kind).toBe('matrix');
  });

  it('passes the config through to the factory', () => {
    let received: ConnectorConfig | null = null;
    registerConnector('matrix', (cfg) => {
      received = cfg;
      return fakeConnector(cfg.kind);
    });
    const cfg: ConnectorConfig = {
      kind: 'matrix',
      matrix: {
        homeserverUrl: 'https://matrix.internal',
        userId: '@mos:internal',
        roomId: '!room:internal',
      },
    };
    createConnector(cfg);
    expect(received).toEqual(cfg);
  });
});
