import { describe, expect, it, vi } from 'vitest';
import type {
  ICommandHostContext,
  IEditCheckpointRestoreResult,
} from '@robota-sdk/agent-framework';
import { SystemCommandExecutor } from '@robota-sdk/agent-framework';
import { createModeCommandModule } from '../mode-command-module.js';

type TPermissionModeName = 'plan' | 'default' | 'acceptEdits' | 'bypassPermissions';
type TSetPermissionModeSpy = ReturnType<typeof vi.fn<(nextMode: TPermissionModeName) => void>>;

function createCheckpointResult(): IEditCheckpointRestoreResult {
  return {
    target: {
      id: 'checkpoint_1',
      sessionId: 'session_1',
      sequence: 1,
      prompt: 'edit files',
      createdAt: '2026-05-03T00:00:00.000Z',
      fileCount: 1,
    },
    restoredCheckpointCount: 0,
    restoredFileCount: 0,
    removedCheckpointCount: 0,
  };
}

function createCommandHostContext(): ICommandHostContext & {
  setPermissionMode: TSetPermissionModeSpy;
} {
  let mode: TPermissionModeName = 'default';
  const setPermissionMode = vi.fn((nextMode: TPermissionModeName) => {
    mode = nextMode;
  });

  return {
    getSession: () => {
      throw new Error('mode command should use the permission mode adapter');
    },
    getCommandHostAdapters: () => ({
      permissionMode: {
        getPermissionMode: () => mode,
        setPermissionMode,
        listSessionAllowedTools: () => [],
      },
    }),
    getContextState: () => ({
      usedTokens: 0,
      maxTokens: 1,
      usedPercentage: 0,
      remainingPercentage: 100,
    }),
    getAutoCompactThreshold: () => 0.835,
    compactContext: async () => undefined,
    getCwd: () => '/workspace',
    listEditCheckpoints: () => [],
    restoreEditCheckpoint: async () => createCheckpointResult(),
    rollbackEditCheckpoint: async () => createCheckpointResult(),
    getUsedMemoryReferences: () => [],
    recordMemoryEvent: () => undefined,
    listBackgroundTasks: () => [],
    readBackgroundTaskLog: async () => ({ taskId: 'task_1', lines: [] }),
    cancelBackgroundTask: async () => undefined,
    closeBackgroundTask: async () => undefined,
    setPermissionMode,
  };
}

describe('createModeCommandModule', () => {
  it('provides mode metadata and executable command from one module owner', () => {
    const module = createModeCommandModule();
    const command = module.systemCommands?.[0];
    const entry = module.commandSources?.[0]?.getCommands()[0];

    expect(module.name).toBe('agent-command-mode');
    expect(entry).toEqual(
      expect.objectContaining({
        name: 'mode',
        description: 'Show/change permission mode',
        argumentHint: 'plan | default | acceptEdits | bypassPermissions',
        source: 'mode',
        modelInvocable: false,
      }),
    );
    expect(entry?.subcommands?.map((subcommand) => subcommand.name)).toEqual([
      'plan',
      'default',
      'acceptEdits',
      'bypassPermissions',
    ]);
    expect(command).toEqual(
      expect.objectContaining({
        name: 'mode',
        description: 'Show/change permission mode',
        argumentHint: 'plan | default | acceptEdits | bypassPermissions',
        lifecycle: 'inline',
        modelInvocable: false,
      }),
    );
    expect(command?.subcommands).toEqual(entry?.subcommands);
  });

  it('reports the current permission mode through the SDK command adapter', async () => {
    const executor = new SystemCommandExecutor([
      ...(createModeCommandModule().systemCommands ?? []),
    ]);

    const result = await executor.execute('mode', createCommandHostContext(), '');

    expect(result?.success).toBe(true);
    expect(result?.message).toBe('Current mode: default');
    expect(result?.data?.mode).toBe('default');
  });

  it('updates valid permission modes through the SDK command adapter', async () => {
    const executor = new SystemCommandExecutor([
      ...(createModeCommandModule().systemCommands ?? []),
    ]);
    const context = createCommandHostContext();

    const result = await executor.execute('mode', context, 'plan');

    expect(result?.success).toBe(true);
    expect(result?.message).toBe('Permission mode set to: plan');
    expect(result?.data?.mode).toBe('plan');
    expect(context.setPermissionMode).toHaveBeenCalledWith('plan');
  });

  it('rejects invalid permission modes without writing state', async () => {
    const executor = new SystemCommandExecutor([
      ...(createModeCommandModule().systemCommands ?? []),
    ]);
    const context = createCommandHostContext();

    const result = await executor.execute('mode', context, 'invalid');

    expect(result?.success).toBe(false);
    expect(result?.message).toBe(
      'Invalid mode. Valid: plan | default | acceptEdits | bypassPermissions',
    );
    expect(context.setPermissionMode).not.toHaveBeenCalled();
  });
});
