import { describe, it, expect, vi } from 'vitest';

vi.mock('../logger.js', () => ({
  createLogger: () => ({
    fatal: (...args: unknown[]) => console.error(...args),
    error: (...args: unknown[]) => console.error(...args),
    warn: (...args: unknown[]) => console.warn(...args),
    info: (...args: unknown[]) => console.log(...args),
    debug: (...args: unknown[]) => console.log(...args),
    trace: (...args: unknown[]) => console.log(...args),
    pino: {},
  }),
}));

import {
  isFleetConfig,
  fleetConfigToLettaBotConfig,
  wasLoadedFromFleetConfig,
  setLoadedFromFleetConfig,
} from './fleet-adapter.js';

// ---------------------------------------------------------------------------
// isFleetConfig
// ---------------------------------------------------------------------------

describe('isFleetConfig', () => {
  it('returns true for a fleet config with llm_config', () => {
    expect(
      isFleetConfig({
        agents: [
          {
            name: 'bot',
            llm_config: { model: 'gpt-4' },
            system_prompt: { value: 'hi' },
            lettabot: { channels: {} },
          },
        ],
      }),
    ).toBe(true);
  });

  it('returns true for a fleet config with system_prompt only', () => {
    expect(
      isFleetConfig({
        agents: [{ name: 'bot', system_prompt: { value: 'hi' }, lettabot: { channels: {} } }],
      }),
    ).toBe(true);
  });

  it('returns false for native LettaBot single-agent config', () => {
    expect(
      isFleetConfig({
        server: { mode: 'api' },
        agent: { name: 'Bot' },
        channels: { telegram: { enabled: true, token: 'abc' } },
      }),
    ).toBe(false);
  });

  it('returns false for native LettaBot multi-agent config', () => {
    expect(
      isFleetConfig({
        server: { mode: 'api' },
        agents: [
          { name: 'Bot1', channels: { telegram: { enabled: true } } },
        ],
      }),
    ).toBe(false);
  });

  it('returns false when fleet-only fields exist but lettabot section is missing', () => {
    expect(
      isFleetConfig({
        agents: [{ name: 'bot', llm_config: { model: 'gpt-4' }, system_prompt: { value: 'hi' } }],
      }),
    ).toBe(false);
  });

  it('returns false when lettabot is an array', () => {
    expect(
      isFleetConfig({
        agents: [{ name: 'bot', llm_config: { model: 'gpt-4' }, lettabot: [] }],
      }),
    ).toBe(false);
  });

  it('returns false for null', () => {
    expect(isFleetConfig(null)).toBe(false);
  });

  it('returns false for empty object', () => {
    expect(isFleetConfig({})).toBe(false);
  });

  it('returns false for empty agents array', () => {
    expect(isFleetConfig({ agents: [] })).toBe(false);
  });

  it('returns false for an array', () => {
    expect(isFleetConfig([{ llm_config: {} }])).toBe(false);
  });
});

// ---------------------------------------------------------------------------
// fleetConfigToLettaBotConfig — single agent
// ---------------------------------------------------------------------------

describe('fleetConfigToLettaBotConfig (single agent)', () => {
  it('converts a single qualifying agent to single-agent format', () => {
    const fleet = {
      agents: [
        {
          name: 'MyBot',
          description: 'Test bot',
          llm_config: { model: 'gpt-4', context_window: 128000 },
          system_prompt: { value: 'You are helpful' },
          tools: ['web_search'],
          lettabot: {
            server: { mode: 'docker', baseUrl: 'http://localhost:8283' },
            displayName: 'Bot',
            channels: {
              telegram: { enabled: true, token: 'tg-token', dmPolicy: 'open' },
            },
            features: { cron: true },
          },
        },
      ],
    };

    const result = fleetConfigToLettaBotConfig(fleet);

    expect(result.agent.name).toBe('MyBot');
    expect(result.agent.displayName).toBe('Bot');
    expect(result.server.mode).toBe('docker');
    expect(result.server.baseUrl).toBe('http://localhost:8283');
    expect(result.channels.telegram?.token).toBe('tg-token');
    expect(result.channels.telegram?.dmPolicy).toBe('open');
    expect(result.features?.cron).toBe(true);
    // lettactl-only fields should NOT be present
    expect((result as any).description).toBeUndefined();
    expect((result as any).llm_config).toBeUndefined();
    expect((result as any).system_prompt).toBeUndefined();
    expect((result as any).tools).toBeUndefined();
  });

  it('maps all lettabot fields correctly', () => {
    const fleet = {
      agents: [
        {
          name: 'FullBot',
          llm_config: { model: 'gpt-4' },
          lettabot: {
            server: { mode: 'api', apiKey: 'sk-test', logLevel: 'debug' },
            displayName: 'Full',
            conversations: { mode: 'per-channel', heartbeat: 'dedicated' },
            channels: {
              slack: { enabled: true, appToken: 'xapp-1', botToken: 'xoxb-1' },
            },
            features: {
              heartbeat: { enabled: true, intervalMin: 15 },
              maxToolCalls: 50,
              display: { showToolCalls: true },
            },
            providers: [{ id: 'anthropic', name: 'anthropic', type: 'anthropic', apiKey: 'sk-ant' }],
            polling: { gmail: { enabled: true, account: 'user@gmail.com' } },
            transcription: { provider: 'openai', apiKey: 'sk-oai' },
            attachments: { maxMB: 10, maxAgeDays: 7 },
            tts: { provider: 'openai', apiKey: 'sk-openai-tts', voiceId: 'alloy', model: 'gpt-4o-mini-tts' },
            integrations: { google: { enabled: true, account: 'user@gmail.com' } },
            security: { redaction: { secrets: true, pii: true } },
          },
        },
      ],
    };

    const result = fleetConfigToLettaBotConfig(fleet);

    expect(result.server.apiKey).toBe('sk-test');
    expect(result.server.logLevel).toBe('debug');
    expect(result.conversations?.mode).toBe('per-channel');
    expect(result.conversations?.heartbeat).toBe('dedicated');
    expect(result.channels.slack?.appToken).toBe('xapp-1');
    expect(result.features?.heartbeat?.intervalMin).toBe(15);
    expect(result.features?.maxToolCalls).toBe(50);
    expect(result.features?.display?.showToolCalls).toBe(true);
    expect(result.providers).toHaveLength(1);
    expect(result.providers![0].apiKey).toBe('sk-ant');
    expect(result.polling?.gmail?.account).toBe('user@gmail.com');
    expect(result.transcription?.provider).toBe('openai');
    expect(result.attachments?.maxMB).toBe(10);
    expect(result.tts?.provider).toBe('openai');
    expect(result.integrations?.google?.enabled).toBe(true);
    expect(result.security?.redaction?.secrets).toBe(true);
  });

  it('skips agents without lettabot section', () => {
    const fleet = {
      agents: [
        {
          name: 'ServerOnly',
          llm_config: { model: 'gpt-4' },
          system_prompt: { value: 'no lettabot' },
        },
        {
          name: 'WithBot',
          llm_config: { model: 'gpt-4' },
          system_prompt: { value: 'has lettabot' },
          lettabot: {
            channels: { telegram: { enabled: true, token: 'tg' } },
          },
        },
      ],
    };

    const result = fleetConfigToLettaBotConfig(fleet);
    expect(result.agent.name).toBe('WithBot');
    expect(result.channels.telegram?.token).toBe('tg');
    // Should be single-agent format (not multi-agent) since only one qualifies
    expect(result.agents).toBeUndefined();
  });

  it('throws when an agent with lettabot section is missing name', () => {
    const fleet = {
      agents: [
        {
          llm_config: { model: 'gpt-4' },
          lettabot: { channels: {} },
        },
      ],
    };

    expect(() => fleetConfigToLettaBotConfig(fleet as any)).toThrow(/missing required `name`/);
  });

  it('ignores agents with array-typed lettabot section', () => {
    const fleet = {
      agents: [
        { name: 'Bad', llm_config: { model: 'gpt-4' }, lettabot: [] },
        { name: 'Good', llm_config: { model: 'gpt-4' }, lettabot: { channels: {} } },
      ],
    };

    const result = fleetConfigToLettaBotConfig(fleet as any);
    expect(result.agent.name).toBe('Good');
  });

  it('throws when no agents have lettabot section', () => {
    const fleet = {
      agents: [
        { name: 'Bot1', llm_config: { model: 'gpt-4' } },
        { name: 'Bot2', llm_config: { model: 'gpt-4' } },
      ],
    };

    expect(() => fleetConfigToLettaBotConfig(fleet)).toThrow(
      /No agents in fleet config have a `lettabot:` section/,
    );
  });

  it('defaults to empty channels when lettabot has no channels', () => {
    const fleet = {
      agents: [
        {
          name: 'MinimalBot',
          llm_config: { model: 'gpt-4' },
          lettabot: {
            server: { mode: 'docker', baseUrl: 'http://localhost:8283' },
          },
        },
      ],
    };

    const result = fleetConfigToLettaBotConfig(fleet);
    expect(result.channels).toEqual({});
  });
});

// ---------------------------------------------------------------------------
// fleetConfigToLettaBotConfig — multi-agent
// ---------------------------------------------------------------------------

describe('fleetConfigToLettaBotConfig (multi-agent)', () => {
  it('converts multiple qualifying agents to multi-agent format', () => {
    const fleet = {
      agents: [
        {
          name: 'Bot1',
          llm_config: { model: 'gpt-4' },
          lettabot: {
            server: { mode: 'docker', baseUrl: 'http://localhost:8283' },
            displayName: 'First',
            channels: { telegram: { enabled: true, token: 'tg1' } },
            providers: [{ id: 'oai', name: 'openai', type: 'openai', apiKey: 'sk-1' }],
            transcription: { provider: 'openai' },
            attachments: { maxMB: 5 },
            tts: { provider: 'openai' },
            integrations: { google: { enabled: true, account: 'multi@gmail.com' } },
            security: { redaction: { secrets: true } },
          },
        },
        {
          name: 'Bot2',
          llm_config: { model: 'claude-3' },
          lettabot: {
            displayName: 'Second',
            channels: { slack: { enabled: true, appToken: 'xapp', botToken: 'xoxb' } },
            features: { cron: true },
          },
        },
      ],
    };

    const result = fleetConfigToLettaBotConfig(fleet);

    // Should be multi-agent format
    expect(result.agents).toHaveLength(2);
    expect(result.agents![0].name).toBe('Bot1');
    expect(result.agents![0].displayName).toBe('First');
    expect(result.agents![0].channels.telegram?.token).toBe('tg1');
    expect(result.agents![1].name).toBe('Bot2');
    expect(result.agents![1].displayName).toBe('Second');
    expect(result.agents![1].channels.slack?.appToken).toBe('xapp');
    expect(result.agents![1].features?.cron).toBe(true);
    expect(result.agents![0].security?.redaction?.secrets).toBe(true);

    // System-wide fields promoted from first agent
    expect(result.server.mode).toBe('docker');
    expect(result.server.baseUrl).toBe('http://localhost:8283');
    expect(result.providers).toHaveLength(1);
    expect(result.transcription?.provider).toBe('openai');
    expect(result.attachments?.maxMB).toBe(5);
    expect(result.tts?.provider).toBe('openai');
    expect(result.integrations?.google?.enabled).toBe(true);
    expect(result.agent.name).toBe('LettaBot');
  });
});

// ---------------------------------------------------------------------------
// wasLoadedFromFleetConfig / setLoadedFromFleetConfig
// ---------------------------------------------------------------------------

describe('wasLoadedFromFleetConfig', () => {
  it('defaults to false', () => {
    setLoadedFromFleetConfig(false);
    expect(wasLoadedFromFleetConfig()).toBe(false);
  });

  it('can be set to true', () => {
    setLoadedFromFleetConfig(true);
    expect(wasLoadedFromFleetConfig()).toBe(true);
    // Clean up
    setLoadedFromFleetConfig(false);
  });
});
