import { describe, expect, test } from 'vitest';

import {
  normalizeCodexJsonLine,
  normalizeOpenCodeEvent,
} from '../../src/agent-events';

describe('agent event normalization', () => {
  test('normalizes Codex assistant deltas and session ids', () => {
    expect(
      normalizeCodexJsonLine(
        JSON.stringify({
          type: 'session.created',
          session_id: 'codex-session-1',
        }),
      ),
    ).toContainEqual({ kind: 'session', sessionId: 'codex-session-1' });

    expect(
      normalizeCodexJsonLine(
        JSON.stringify({
          type: 'response.output_text.delta',
          delta: 'hello',
        }),
      ),
    ).toContainEqual({ kind: 'assistant_delta', content: 'hello' });
  });

  test('normalizes legacy codex-rs msg-wrapped events', () => {
    expect(
      normalizeCodexJsonLine(
        JSON.stringify({
          id: '0',
          msg: { type: 'agent_message', message: 'hello there' },
        }),
      ),
    ).toContainEqual({ kind: 'assistant_delta', content: 'hello there\n\n' });

    expect(
      normalizeCodexJsonLine(
        JSON.stringify({
          id: '1',
          msg: { type: 'error', message: 'usage limit reached' },
        }),
      ),
    ).toContainEqual({ kind: 'error', message: 'usage limit reached' });

    expect(
      normalizeCodexJsonLine(
        JSON.stringify({ id: '2', msg: { type: 'task_complete' } }),
      ),
    ).toContainEqual({ kind: 'assistant_completed' });
  });

  test('normalizes Codex CLI thread lifecycle events', () => {
    expect(
      normalizeCodexJsonLine(
        JSON.stringify({
          type: 'thread.started',
          thread_id: '019ef701-f7d7-76a0-a96b-15c059631dd9',
        }),
      ),
    ).toContainEqual({
      kind: 'session',
      sessionId: '019ef701-f7d7-76a0-a96b-15c059631dd9',
    });

    expect(
      normalizeCodexJsonLine(
        JSON.stringify({
          type: 'turn.started',
        }),
      ),
    ).toContainEqual({ kind: 'status', status: 'turn.started' });

    expect(
      normalizeCodexJsonLine(
        JSON.stringify({
          type: 'turn.completed',
        }),
      ),
    ).toContainEqual({ kind: 'assistant_completed' });
  });

  test('normalizes Codex command and file events', () => {
    expect(
      normalizeCodexJsonLine(
        JSON.stringify({
          type: 'command.completed',
          command: 'bun test',
          output: 'ok',
        }),
      ),
    ).toContainEqual({
      kind: 'command_executed',
      command: 'bun test',
      output: 'ok',
    });

    expect(
      normalizeCodexJsonLine(
        JSON.stringify({
          type: 'file.edited',
          path: 'src/app.ts',
        }),
      ),
    ).toContainEqual({ kind: 'file_edited', path: 'src/app.ts' });
  });

  test('normalizes current Codex item events', () => {
    expect(
      normalizeCodexJsonLine(
        JSON.stringify({
          type: 'item.completed',
          item: {
            id: 'item-1',
            type: 'agent_message',
            text: 'I updated the auth provider.',
          },
        }),
      ),
    ).toContainEqual({
      kind: 'assistant_delta',
      content: 'I updated the auth provider.\n\n',
      externalMessageId: 'item-1',
    });

    expect(
      normalizeCodexJsonLine(
        JSON.stringify({
          type: 'item.completed',
          item: {
            id: 'item-2',
            type: 'error',
            message: 'sandbox failed',
          },
        }),
      ),
    ).toContainEqual({
      kind: 'error',
      message: 'sandbox failed',
    });

    expect(
      normalizeCodexJsonLine(
        JSON.stringify({
          type: 'turn.failed',
          error: { message: 'request failed' },
        }),
      ),
    ).toContainEqual({
      kind: 'error',
      message: '{\n  "message": "request failed"\n}',
    });

    expect(
      normalizeCodexJsonLine(
        JSON.stringify({
          type: 'item.completed',
          item: {
            id: 'item-warning',
            type: 'error',
            message:
              '`[features].codex_hooks` is deprecated. Use `[features].hooks` instead.',
          },
        }),
      ),
    ).toContainEqual({
      kind: 'status',
      status:
        '`[features].codex_hooks` is deprecated. Use `[features].hooks` instead.',
    });
  });

  test('normalizes Codex tool item lifecycle events', () => {
    expect(
      normalizeCodexJsonLine(
        JSON.stringify({
          type: 'item.started',
          item: {
            id: 'tool-1',
            type: 'local_shell_call',
            command: ['bash', '-lc', 'rg Authentik'],
          },
        }),
      ),
    ).toContainEqual({
      kind: 'tool_started',
      name: 'Command',
      input: 'bash -lc rg Authentik',
      externalMessageId: 'tool-1',
    });

    expect(
      normalizeCodexJsonLine(
        JSON.stringify({
          type: 'item.completed',
          item: {
            id: 'tool-1',
            type: 'local_shell_call',
            command: ['bash', '-lc', 'rg Authentik'],
            output: 'apps/web/auth.ts',
          },
        }),
      ),
    ).toContainEqual({
      kind: 'tool_completed',
      name: 'Command',
      output: 'apps/web/auth.ts',
      externalMessageId: 'tool-1',
    });

    expect(
      normalizeCodexJsonLine(
        JSON.stringify({
          type: 'item.completed',
          item: {
            id: 'tool-2',
            type: 'exec_command',
            command: 'cat package.json',
            aggregated_output: '{"scripts":{"build":"turbo build"}}',
            exit_code: 0,
          },
        }),
      ),
    ).toContainEqual({
      kind: 'tool_completed',
      name: 'Command',
      output: '{"scripts":{"build":"turbo build"}}',
      externalMessageId: 'tool-2',
    });
  });

  test('normalizes OpenCode assistant, tool, and permission events', () => {
    expect(
      normalizeOpenCodeEvent({
        type: 'message.part.delta',
        properties: {
          part: { text: 'streamed' },
          messageID: 'message-1',
        },
      }),
    ).toContainEqual({
      kind: 'assistant_delta',
      content: 'streamed',
      externalMessageId: 'message-1',
    });

    expect(
      normalizeOpenCodeEvent({
        type: 'tool.started',
        properties: { tool: 'edit', input: { path: 'README.md' } },
      }),
    ).toContainEqual({
      kind: 'tool_started',
      name: 'edit',
      input: '{\n  "path": "README.md"\n}',
      externalMessageId: '',
    });

    expect(
      normalizeOpenCodeEvent({
        type: 'permission.asked',
        properties: {
          permissionID: 'perm-1',
          message: 'Run bun test?',
        },
      }),
    ).toContainEqual({
      kind: 'permission_requested',
      externalRequestId: 'perm-1',
      title: 'Permission requested',
      body: 'Run bun test?',
      metadata:
        '{\n  "permissionID": "perm-1",\n  "message": "Run bun test?"\n}',
    });

    expect(
      normalizeOpenCodeEvent({
        type: 'tool.output',
        properties: {
          tool: 'read',
          output: 'apps/web/auth.ts',
          messageID: 'message-2',
        },
      }),
    ).toContainEqual({
      kind: 'tool_completed',
      name: 'read',
      output: 'apps/web/auth.ts',
      externalMessageId: 'message-2',
    });
  });
});
