import { describe, it, expect } from 'vitest';
import { discoverServices } from './services.js';
import { ChannelRegistry } from '../../channels/registry.js';
import type { Config } from '../../config/index.js';

function makeBaseConfig(): Config {
  return {
    server: { localhost: true, port: 18800 },
    models: { default: { provider: 'anthropic', model: 'claude-sonnet-4', api_key: 'sk-test' }, fallback_chain: ['anthropic'] },
    backends: { native: { enabled: true }, opencode: { enabled: false }, claude_code: { enabled: false } },
    hooks: { confirm: [], log: [], silent: [] },
    mcp: { servers: [] },
    automation: {
      cron: [],
      webhooks: [],
      gmail: undefined,
      heartbeat: undefined,
      gcal: undefined,
      gdocs: undefined,
      gdrive: undefined,
      gtasks: undefined,
    },
    telegram: undefined,
    discord: undefined,
    slack: undefined,
    whatsapp: undefined,
    matrix: undefined,
  } as unknown as Config;
}

describe('discoverServices', () => {
  it('includes known services and marks not_configured when disabled', () => {
    const cfg = makeBaseConfig();
    const reg = new ChannelRegistry();

    const services = discoverServices(cfg, reg);

    expect(services).toEqual(expect.arrayContaining([
      expect.objectContaining({ name: 'telegram', status: 'not_configured' }),
      expect.objectContaining({ name: 'matrix', status: 'not_configured' }),
      expect.objectContaining({ name: 'cron', status: 'not_configured' }),
      expect.objectContaining({ name: 'mcp', status: 'not_configured' }),
      expect.objectContaining({ name: 'web_search', status: 'configured' }),
      expect.objectContaining({ name: 'audio_transcription', status: 'not_configured' }),
    ]));
  });

  it('marks configured channels as disconnected when adapter is not registered', () => {
    const cfg = makeBaseConfig();
    (cfg as any).telegram = { bot_token: 'x', allowed_chat_ids: [123] };

    const reg = new ChannelRegistry();
    const services = discoverServices(cfg, reg);

    expect(services.find(s => s.name === 'telegram')?.status).toBe('disconnected');
  });

  it('uses adapter status when channel adapter is registered', () => {
    const cfg = makeBaseConfig();
    (cfg as any).telegram = { bot_token: 'x', allowed_chat_ids: [123] };

    const reg = new ChannelRegistry();
    reg.register({
      name: 'telegram',
      status: 'connected',
      connect: async () => {},
      disconnect: async () => {},
      send: async () => {},
      onMessage: () => {},
    });

    const services = discoverServices(cfg, reg);
    expect(services.find(s => s.name === 'telegram')?.status).toBe('connected');
  });

  it('marks enabled automation subsystems as configured and carries item counts', () => {
    const cfg = makeBaseConfig();
    cfg.automation.cron = [
      { name: 'job', schedule: '0 0 * * *', message: 'hi', output: { channel: 'webchat', peer: 'x' }, enabled: true },
    ] as any;
    cfg.mcp.servers = [{ name: 'srv', command: 'x', args: [] }] as any;

    const reg = new ChannelRegistry();
    const services = discoverServices(cfg, reg);

    expect(services.find(s => s.name === 'cron')?.status).toBe('configured');
    expect(services.find(s => s.name === 'cron')?.itemCount).toBe(1);
    expect(services.find(s => s.name === 'mcp')?.metadata).toEqual({ serverCount: 1 });
  });

  it('marks audio transcription as configured and includes endpoint metadata', () => {
    const cfg = makeBaseConfig();
    (cfg as any).audio = { enabled: true, provider: { type: 'custom', endpoint: 'http://localhost:18801/v1/audio/transcriptions', model: 'whisper-1' } };

    const reg = new ChannelRegistry();
    const services = discoverServices(cfg, reg);

    const audio = services.find(s => s.name === 'audio_transcription');
    expect(audio?.status).toBe('configured');
    expect(audio?.metadata).toMatchObject({
      provider: 'custom',
      endpoint: 'http://localhost:18801/v1/audio/transcriptions',
      model: 'whisper-1',
    });
  });
});
