import { describe, expect, it } from 'vitest';
import type {
  AgentRuntimeProvider,
  RuntimeAttachHandle,
  RuntimeAttachMode,
  RuntimeCapabilitySet,
  RuntimeHealth,
  RuntimeMessage,
  RuntimeScope,
  RuntimeSession,
  RuntimeSessionTree,
  RuntimeStreamEvent,
} from '@mosaicstack/types';
import { AgentRuntimeProviderRegistry } from './runtime-provider-registry.js';

class TestRuntimeProvider implements AgentRuntimeProvider {
  readonly id = 'test-runtime';

  async capabilities(_scope: RuntimeScope): Promise<RuntimeCapabilitySet> {
    return { supported: ['session.list'] };
  }

  async health(_scope: RuntimeScope): Promise<RuntimeHealth> {
    return { status: 'healthy', checkedAt: '2026-07-12T00:00:00.000Z' };
  }

  async listSessions(_scope: RuntimeScope): Promise<RuntimeSession[]> {
    return [];
  }

  async getSessionTree(_scope: RuntimeScope): Promise<RuntimeSessionTree[]> {
    return [];
  }

  async *streamSession(
    _sessionId: string,
    _cursor: string | undefined,
    _scope: RuntimeScope,
  ): AsyncIterable<RuntimeStreamEvent> {
    return;
  }

  async sendMessage(
    _sessionId: string,
    _message: RuntimeMessage,
    _scope: RuntimeScope,
  ): Promise<void> {}

  async attach(
    _sessionId: string,
    _mode: RuntimeAttachMode,
    _scope: RuntimeScope,
  ): Promise<RuntimeAttachHandle> {
    return {
      attachmentId: 'attachment-1',
      sessionId: 'session-1',
      mode: 'read',
      expiresAt: '2026-07-12T00:00:00.000Z',
    };
  }

  async detach(_attachmentId: string, _scope: RuntimeScope): Promise<void> {}

  async terminate(_sessionId: string, _approvalRef: string, _scope: RuntimeScope): Promise<void> {}
}

describe('AgentRuntimeProviderRegistry', (): void => {
  it('resolves only registered runtime providers', (): void => {
    const registry = new AgentRuntimeProviderRegistry();
    const provider = new TestRuntimeProvider();

    registry.register(provider);

    expect(registry.get(provider.id)).toBe(provider);
    expect(registry.get('unknown-runtime')).toBeUndefined();
    expect(registry.list()).toEqual([provider]);
  });

  it('rejects duplicate and blank provider identities rather than silently replacing a runtime', (): void => {
    const registry = new AgentRuntimeProviderRegistry();
    const provider = new TestRuntimeProvider();

    registry.register(provider);

    expect((): void => {
      registry.register(provider);
    }).toThrow(/already registered/);
    expect((): void => {
      registry.require('');
    }).toThrow(/provider ID is required/);
    expect((): void => {
      registry.require('unknown-runtime');
    }).toThrow(/not registered/);
  });
});
