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

import { createContextCommand, createElevateCommand, createModelCommand, createQueueCommand, createResearchCommand } from './index.js';

describe('builtin /model command', () => {
  it('passes through the full argument string', async () => {
    const cmd = createModelCommand();
    const setModel = vi.fn(() => 'ok');

    const result = await cmd.execute(['default', 'github/gpt-5-mini'], {
      channel: 'test',
      senderId: 'user',
      sessionId: 's1',
      rawInput: '/model default github/gpt-5-mini',
      services: { setModel },
    });

    expect(setModel).toHaveBeenCalledWith('default github/gpt-5-mini');
    expect(result).toEqual({ handled: true, text: 'ok' });
  });

  it('still works for single-argument tier switching', async () => {
    const cmd = createModelCommand();
    const setModel = vi.fn(() => 'switched');

    const result = await cmd.execute(['fast'], {
      channel: 'test',
      senderId: 'user',
      sessionId: 's1',
      rawInput: '/model fast',
      services: { setModel },
    });

    expect(setModel).toHaveBeenCalledWith('fast');
    expect(result).toEqual({ handled: true, text: 'switched' });
  });
});

describe('builtin /research command', () => {
  it('delegates to the research agent with the full task string', async () => {
    const cmd = createResearchCommand();
    const delegateAgent = vi.fn(() => 'research output');

    const result = await cmd.execute(['compare', 'k0s', 'vs', 'k3s'], {
      channel: 'test',
      senderId: 'user',
      sessionId: 's1',
      rawInput: '/research compare k0s vs k3s',
      services: { delegateAgent },
    });

    expect(delegateAgent).toHaveBeenCalledWith('research', 'compare k0s vs k3s');
    expect(result).toEqual({ handled: true, text: 'research output' });
  });

  it('returns usage when no task is provided', async () => {
    const cmd = createResearchCommand();
    const result = await cmd.execute([], {
      channel: 'test',
      senderId: 'user',
      sessionId: 's1',
      rawInput: '/research',
      services: {},
    });
    expect(result).toEqual({ handled: true, text: 'Usage: /research <question or task>' });
  });
});

describe('builtin /elevate command', () => {
  it('passes through the full argument string', async () => {
    const cmd = createElevateCommand();
    const setElevation = vi.fn(() => 'ok');

    const result = await cmd.execute(['10m', 'reason', '--yes'], {
      channel: 'test',
      senderId: 'user',
      sessionId: 's1',
      rawInput: '/elevate 10m reason --yes',
      services: { setElevation },
    });

    expect(setElevation).toHaveBeenCalledWith('10m reason --yes');
    expect(result).toEqual({ handled: true, text: 'ok' });
  });

  it('shows status when no args are provided', async () => {
    const cmd = createElevateCommand();
    const getElevation = vi.fn(() => 'status');
    const result = await cmd.execute([], {
      channel: 'test',
      senderId: 'user',
      sessionId: 's1',
      rawInput: '/elevate',
      services: { getElevation },
    });
    expect(getElevation).toHaveBeenCalledOnce();
    expect(result).toEqual({ handled: true, text: 'status' });
  });
});

describe('builtin /queue command', () => {
  it('shows queue status with no args', async () => {
    const cmd = createQueueCommand();
    const getQueue = vi.fn(() => 'queue status');
    const result = await cmd.execute([], {
      channel: 'test',
      senderId: 'user',
      sessionId: 's1',
      rawInput: '/queue',
      services: { getQueue },
    });
    expect(getQueue).toHaveBeenCalledOnce();
    expect(result).toEqual({ handled: true, text: 'queue status' });
  });

  it('passes through set operations', async () => {
    const cmd = createQueueCommand();
    const setQueue = vi.fn(() => 'updated');
    const result = await cmd.execute(['set', 'mode', 'followup'], {
      channel: 'test',
      senderId: 'user',
      sessionId: 's1',
      rawInput: '/queue set mode followup',
      services: { setQueue },
    });
    expect(setQueue).toHaveBeenCalledWith('mode followup');
    expect(result).toEqual({ handled: true, text: 'updated' });
  });

  it('calls reset operation', async () => {
    const cmd = createQueueCommand();
    const resetQueue = vi.fn(() => 'reset');
    const result = await cmd.execute(['reset'], {
      channel: 'test',
      senderId: 'user',
      sessionId: 's1',
      rawInput: '/queue reset',
      services: { resetQueue },
    });
    expect(resetQueue).toHaveBeenCalledOnce();
    expect(result).toEqual({ handled: true, text: 'reset' });
  });
});

describe('builtin /context command', () => {
  it('returns context usage text from services', async () => {
    const cmd = createContextCommand();
    const getContext = vi.fn(() => 'Context Usage\n\n75.0%');
    const result = await cmd.execute([], {
      channel: 'test',
      senderId: 'user',
      sessionId: 's1',
      rawInput: '/context',
      services: { getContext },
    });
    expect(getContext).toHaveBeenCalledOnce();
    expect(result).toEqual({ handled: true, text: 'Context Usage\n\n75.0%' });
  });

  it('returns not-available when service is missing', async () => {
    const cmd = createContextCommand();
    const result = await cmd.execute([], {
      channel: 'test',
      senderId: 'user',
      sessionId: 's1',
      rawInput: '/context',
      services: {},
    });
    expect(result).toEqual({ handled: true, text: 'Context command is not available in this session.' });
  });
});
