/**
 * @vitest-environment jsdom
 */
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { h } from 'preact';
import { render, screen, fireEvent, cleanup, waitFor, act } from '@testing-library/preact';

vi.mock('react-i18next', () => ({
  useTranslation: () => ({
    t: (key: string, _opts?: Record<string, unknown>) => {
      if (key === 'session.agentGroup.transport_sdk') return 'SDK';
      if (key === 'session.agentGroup.cli_process') return 'CLI';
      // Return last segment of key as simple translation
      const parts = key.split('.');
      return parts[parts.length - 1];
    },
  }),
}));

vi.mock('../../src/components/FileBrowser.js', () => ({
  FileBrowser: () => null,
}));

vi.mock('../../src/components/file-browser-lazy.js', () => ({
  FileBrowser: (props: {
    onConfirm?: (paths: string[]) => void;
    onDirectoryCreated?: (path: string) => void;
  }) => (
    <div data-testid="mock-file-browser">
      <button onClick={() => props.onConfirm?.(['/home/user/selected'])}>mock-select-dir</button>
      <button onClick={() => props.onDirectoryCreated?.('/home/user/new-project')}>mock-create-folder</button>
    </div>
  ),
}));

import { NewSessionDialog } from '../../src/components/NewSessionDialog.js';

const makeWs = () => {
  const handlers = new Set<(msg: unknown) => void>();
  return {
    sendSessionCommand: vi.fn(),
    send: vi.fn(),
    requestSessionList: vi.fn(),
    connected: true,
    onMessage: vi.fn((handler: (msg: unknown) => void) => {
      handlers.add(handler);
      return () => handlers.delete(handler);
    }),
    emit: (msg: unknown) => {
      handlers.forEach((handler) => handler(msg));
    },
    subSessionDetectShells: vi.fn(),
  };
};

describe('NewSessionDialog', () => {
  afterEach(() => {
    cleanup();
  });

  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('renders project name input', () => {
    render(<NewSessionDialog ws={makeWs() as any} onClose={vi.fn()} onSessionStarted={vi.fn()} isProviderConnected={() => false} />);
    expect(screen.getByPlaceholderText('my-project')).toBeDefined();
  });

  it('renders working directory input', () => {
    render(<NewSessionDialog ws={makeWs() as any} onClose={vi.fn()} onSessionStarted={vi.fn()} isProviderConnected={() => false} />);
    expect(screen.getByPlaceholderText('~/projects/my-project')).toBeDefined();
  });

  it('uses a newly created folder from the directory picker as the working directory', async () => {
    render(<NewSessionDialog ws={makeWs() as any} onClose={vi.fn()} onSessionStarted={vi.fn()} isProviderConnected={() => false} />);

    fireEvent.click(screen.getByTitle('browse'));
    fireEvent.click(screen.getByText('mock-create-folder'));

    await waitFor(() => {
      expect((screen.getByPlaceholderText('~/projects/my-project') as HTMLInputElement).value).toBe('/home/user/new-project');
    });
    expect(screen.queryByTestId('mock-file-browser')).toBeNull();
  });

  it('renders agent type selector', () => {
    render(<NewSessionDialog ws={makeWs() as any} onClose={vi.fn()} onSessionStarted={vi.fn()} isProviderConnected={() => false} />);
    const select = screen.getAllByRole('combobox')[0] as HTMLSelectElement;
    expect(select).toBeDefined();
  });

  it('agent type selector separates transport/sdk and cli/process groups', () => {
    render(<NewSessionDialog ws={makeWs() as any} onClose={vi.fn()} onSessionStarted={vi.fn()} isProviderConnected={() => false} />);
    const select = screen.getAllByRole('combobox')[0] as HTMLSelectElement;
    const optgroups = Array.from(select.querySelectorAll('optgroup'));
    expect(optgroups.map((group) => group.label)).toEqual(['SDK', 'CLI']);
    const options = Array.from(select.options).map((o) => o.value);
    expect(options.slice(0, 8)).toEqual([
      'claude-code-sdk',
      'codex-sdk',
      'copilot-sdk',
      'cursor-headless',
      'gemini-sdk',
      'kimi-sdk',
      'qwen',
      'openclaw',
    ]);
    expect(options.slice(8)).toEqual([
      'claude-code',
      'codex',
      'opencode',
      'gemini',
    ]);
  });

  it('defaults agent type to claude-code-sdk', () => {
    render(<NewSessionDialog ws={makeWs() as any} onClose={vi.fn()} onSessionStarted={vi.fn()} isProviderConnected={() => false} />);
    const select = screen.getAllByRole('combobox')[0] as HTMLSelectElement;
    expect(select.value).toBe('claude-code-sdk');
    expect(screen.getByText('agent_flavor_sdk')).toBeDefined();
    expect(screen.getByText('qwen_provider_hint')).toBeDefined();
  });

  it('cancel button calls onClose', () => {
    const onClose = vi.fn();
    render(<NewSessionDialog ws={makeWs() as any} onClose={onClose} onSessionStarted={vi.fn()} isProviderConnected={() => false} />);
    fireEvent.click(screen.getByRole('button', { name: /cancel/i }));
    expect(onClose).toHaveBeenCalledOnce();
  });

  it('submit with valid inputs calls ws.sendSessionCommand with correct payload', () => {
    const ws = makeWs();
    render(<NewSessionDialog ws={ws as any} onClose={vi.fn()} onSessionStarted={vi.fn()} isProviderConnected={() => false} />);

    fireEvent.input(screen.getByPlaceholderText('my-project'), {
      target: { value: 'my-app' },
    });
    fireEvent.input(screen.getByPlaceholderText('~/projects/my-project'), {
      target: { value: '~/projects/my-app' },
    });

    fireEvent.click(screen.getByRole('button', { name: /start/i }));

    expect(ws.sendSessionCommand).toHaveBeenCalledOnce();
    expect(ws.sendSessionCommand).toHaveBeenCalledWith('start', {
      project: 'my-app',
      dir: '~/projects/my-app',
      agentType: 'claude-code-sdk',
      thinking: 'high',
    });
  });

  it('shows error when submitting with empty project name', () => {
    const ws = makeWs();
    render(<NewSessionDialog ws={ws as any} onClose={vi.fn()} onSessionStarted={vi.fn()} isProviderConnected={() => false} />);
    // Clear the project field (it's empty by default)
    fireEvent.click(screen.getByRole('button', { name: /start/i }));
    expect(ws.sendSessionCommand).not.toHaveBeenCalled();
    // t('new_session.project_required') → 'project_required' via mock
    expect(screen.getByText('project_required')).toBeDefined();
  });

  it('shows error when not connected', () => {
    const ws = { sendSessionCommand: vi.fn(), connected: false, onMessage: vi.fn().mockReturnValue(() => {}) };
    render(<NewSessionDialog ws={ws as any} onClose={vi.fn()} onSessionStarted={vi.fn()} isProviderConnected={() => false} />);

    fireEvent.input(screen.getByPlaceholderText('my-project'), {
      target: { value: 'my-app' },
    });

    fireEvent.click(screen.getByRole('button', { name: /start/i }));
    expect(ws.sendSessionCommand).not.toHaveBeenCalled();
    // t('new_session.daemon_offline') → 'daemon_offline' via mock
    expect(screen.getByText('daemon_offline')).toBeDefined();
  });

  it('agent type changes when selector is updated', async () => {
    const ws = makeWs();
    render(<NewSessionDialog ws={ws as any} onClose={vi.fn()} onSessionStarted={vi.fn()} isProviderConnected={() => false} />);

    const select = screen.getAllByRole('combobox')[0] as HTMLSelectElement;
    select.value = 'codex';
    fireEvent.input(select, { target: { value: select.value } });
    await waitFor(() => expect(select.value).toBe('codex'));

    fireEvent.input(screen.getByPlaceholderText('my-project'), {
      target: { value: 'test-proj' },
    });
    fireEvent.click(screen.getByRole('button', { name: /start/i }));

    expect(ws.sendSessionCommand).toHaveBeenCalledWith('start', expect.objectContaining({
      agentType: 'codex',
    }));
  });

  it('pressing Escape does not call onClose', () => {
    const onClose = vi.fn();
    const { container } = render(<NewSessionDialog ws={makeWs() as any} onClose={onClose} onSessionStarted={vi.fn()} isProviderConnected={() => false} />);
    const dialog = container.querySelector('[role="dialog"]')!;
    fireEvent.keyDown(dialog, { key: 'Escape' });
    expect(onClose).not.toHaveBeenCalled();
  });

  it('clicking the backdrop does not call onClose', () => {
    const onClose = vi.fn();
    const { container } = render(<NewSessionDialog ws={makeWs() as any} onClose={onClose} onSessionStarted={vi.fn()} isProviderConnected={() => false} />);
    const backdrop = container.querySelector('[role="dialog"]')!;
    fireEvent.click(backdrop, { target: backdrop });
    expect(onClose).not.toHaveBeenCalled();
  });

  it('matches started events for non-ASCII project names deterministically', () => {
    const ws = makeWs();
    const onClose = vi.fn();
    const onSessionStarted = vi.fn();
    render(<NewSessionDialog ws={ws as any} onClose={onClose} onSessionStarted={onSessionStarted} isProviderConnected={() => false} />);

    fireEvent.input(screen.getByPlaceholderText('my-project'), {
      target: { value: '测试' },
    });
    fireEvent.input(screen.getByPlaceholderText('~/projects/my-project'), {
      target: { value: '~/projects/test' },
    });
    fireEvent.click(screen.getByRole('button', { name: /start/i }));

    expect(ws.sendSessionCommand).toHaveBeenCalledWith('start', expect.objectContaining({
      project: '测试',
      agentType: 'claude-code-sdk',
    }));

    act(() => ws.emit({
      type: 'session.event',
      event: 'started',
      session: 'deck_u6d4b_u8bd5_brain',
      state: 'idle',
    }));

    expect(onSessionStarted).toHaveBeenCalledWith('deck_u6d4b_u8bd5_brain');
    expect(onClose).toHaveBeenCalledOnce();
  });

  it('accepts session_list as authoritative startup success after the local wait probe', () => {
    vi.useFakeTimers();
    try {
      const ws = makeWs();
      const onClose = vi.fn();
      const onSessionStarted = vi.fn();
      render(<NewSessionDialog ws={ws as any} onClose={onClose} onSessionStarted={onSessionStarted} isProviderConnected={() => false} />);

      fireEvent.input(screen.getByPlaceholderText('my-project'), {
        target: { value: 'my-app' },
      });
      fireEvent.input(screen.getByPlaceholderText('~/projects/my-project'), {
        target: { value: '~/projects/my-app' },
      });
      fireEvent.click(screen.getByRole('button', { name: /start/i }));

      act(() => {
        vi.advanceTimersByTime(15_000);
      });

      expect(ws.requestSessionList).toHaveBeenCalledOnce();
      expect(screen.queryByText('timeout')).toBeNull();
      expect(onClose).not.toHaveBeenCalled();

      act(() => ws.emit({
        type: 'session_list',
        sessions: [
          {
            name: 'deck_my_app_brain',
            project: 'my-app',
            role: 'brain',
            agentType: 'claude-code-sdk',
            state: 'idle',
          },
        ],
      }));

      expect(onSessionStarted).toHaveBeenCalledWith('deck_my_app_brain');
      expect(onClose).toHaveBeenCalledOnce();
    } finally {
      vi.useRealTimers();
    }
  });

  it('ignores session.error for other projects while a start is pending', () => {
    const ws = makeWs();
    render(<NewSessionDialog ws={ws as any} onClose={vi.fn()} onSessionStarted={vi.fn()} isProviderConnected={() => false} />);

    fireEvent.input(screen.getByPlaceholderText('my-project'), {
      target: { value: 'my-app' },
    });
    fireEvent.input(screen.getByPlaceholderText('~/projects/my-project'), {
      target: { value: '~/projects/my-app' },
    });
    fireEvent.click(screen.getByRole('button', { name: /start/i }));

    act(() => ws.emit({
      type: 'session.error',
      project: 'other-project',
      message: 'Other failed',
    }));
    expect(screen.queryByText('Other failed')).toBeNull();
    expect(screen.getAllByText('starting').length).toBeGreaterThan(0);

    act(() => ws.emit({
      type: 'session.error',
      project: 'my-app',
      message: 'Start failed',
    }));
    expect(screen.getByText('Start failed')).toBeDefined();
  });

  it('shows cli/sdk difference hint when switching agent type', async () => {
    const ws = makeWs();
    render(<NewSessionDialog ws={ws as any} onClose={vi.fn()} onSessionStarted={vi.fn()} isProviderConnected={() => false} />);

    expect(screen.getByText('agent_flavor_sdk')).toBeDefined();

    const select = screen.getAllByRole('combobox')[0] as HTMLSelectElement;
    select.value = 'claude-code';
    fireEvent.input(select, { target: { value: select.value } });

    await waitFor(() => expect(screen.getByText('agent_flavor_cli')).toBeDefined());
  });

  it('shows the qwen provider-specific hint when qwen is selected', async () => {
    const ws = makeWs();
    render(<NewSessionDialog ws={ws as any} onClose={vi.fn()} onSessionStarted={vi.fn()} isProviderConnected={() => false} />);

    const select = screen.getAllByRole('combobox')[0] as HTMLSelectElement;
    fireEvent.input(select, { target: { value: 'qwen' } });

    await waitFor(() => expect(screen.getByText('qwen_provider_selected_hint')).toBeDefined());
  });

  it('includes thinking level when starting codex-sdk', async () => {
    const ws = makeWs();
    render(<NewSessionDialog ws={ws as any} onClose={vi.fn()} onSessionStarted={vi.fn()} isProviderConnected={() => false} />);

    fireEvent.input(screen.getByPlaceholderText('my-project'), { target: { value: 'my-app' } });
    fireEvent.input(screen.getByPlaceholderText('~/projects/my-project'), { target: { value: '~/projects/my-app' } });
    const agentTypeSelect = screen.getAllByRole('combobox')[0] as HTMLSelectElement;
    agentTypeSelect.value = 'codex-sdk';
    fireEvent.input(agentTypeSelect, { target: { value: agentTypeSelect.value } });
    const selects = screen.getAllByRole('combobox') as HTMLSelectElement[];
    fireEvent.input(selects[1], { target: { value: 'high' } });
    fireEvent.click(screen.getByRole('button', { name: /start/i }));

    expect(ws.sendSessionCommand).toHaveBeenCalledWith('start', expect.objectContaining({
      agentType: 'codex-sdk',
      thinking: 'high',
    }));
  });

  it('does not show CC preset controls for claude-code-sdk', () => {
    const ws = makeWs();
    ws.onMessage.mockImplementation((handler: (msg: unknown) => void) => {
      handler({
        type: 'cc.presets.list_response',
        presets: [
          { name: 'MiniMax', env: { ANTHROPIC_MODEL: 'MiniMax-M2.7' } },
        ],
      });
      return () => {};
    });

    render(<NewSessionDialog ws={ws as any} onClose={vi.fn()} onSessionStarted={vi.fn()} isProviderConnected={() => false} />);

    expect(screen.queryByText('api_provider')).toBeNull();
  });

  it('shows CC preset controls and submits preset for qwen', async () => {
    const ws = makeWs();
    ws.onMessage.mockImplementation((handler: (msg: unknown) => void) => {
      handler({
        type: 'cc.presets.list_response',
        presets: [
          {
            name: 'MiniMax',
            env: { ANTHROPIC_MODEL: 'MiniMax-M2.7' },
            defaultModel: 'MiniMax-M2.7',
            availableModels: [{ id: 'MiniMax-M2.7' }, { id: 'MiniMax-Text-01' }],
          },
        ],
      });
      return () => {};
    });

    render(<NewSessionDialog ws={ws as any} onClose={vi.fn()} onSessionStarted={vi.fn()} isProviderConnected={() => false} />);

    const agentTypeSelect = screen.getAllByRole('combobox')[0] as HTMLSelectElement;
    agentTypeSelect.value = 'qwen';
    fireEvent.input(agentTypeSelect, { target: { value: agentTypeSelect.value } });
    await waitFor(() => expect(screen.getByText('compatible_api_via_qwen')).toBeDefined());
    expect(screen.getByText('qwen_provider_selected_hint')).toBeDefined();
    fireEvent.input(screen.getByPlaceholderText('my-project'), { target: { value: 'my-app' } });
    fireEvent.input(screen.getByPlaceholderText('~/projects/my-project'), { target: { value: '~/projects/my-app' } });

    const presetSelect = (screen.getAllByRole('combobox') as HTMLSelectElement[])
      .find((select) => Array.from(select.options).some((option) => option.value === 'MiniMax'));
    expect(presetSelect).toBeDefined();
    presetSelect!.value = 'MiniMax';
    fireEvent.input(presetSelect!, { target: { value: presetSelect!.value } });
    fireEvent.click(screen.getByRole('button', { name: /start/i }));

    expect(ws.sendSessionCommand).toHaveBeenCalledWith('start', expect.objectContaining({
      agentType: 'qwen',
      ccPreset: 'MiniMax',
      requestedModel: 'MiniMax-M2.7',
      thinking: 'high',
    }));
  });

  it('custom provider SDK locks the main-session agent to qwen and uses a preset', async () => {
    const ws = makeWs();
    ws.onMessage.mockImplementation((handler: (msg: unknown) => void) => {
      handler({
        type: 'cc.presets.list_response',
        presets: [
          {
            name: 'MiniMax',
            env: { ANTHROPIC_MODEL: 'MiniMax-M2.7' },
            defaultModel: 'MiniMax-M2.7',
            availableModels: [{ id: 'MiniMax-M2.7' }, { id: 'MiniMax-Text-01' }],
          },
        ],
      });
      return () => {};
    });

    render(<NewSessionDialog ws={ws as any} onClose={vi.fn()} onSessionStarted={vi.fn()} isProviderConnected={() => false} />);

    const agentTypeSelect = screen.getAllByRole('combobox')[0] as HTMLSelectElement;
    fireEvent.click(screen.getByLabelText(/custom_provider_sdk/i));

    await waitFor(() => expect(agentTypeSelect.value).toBe('qwen'));
    expect(agentTypeSelect.disabled).toBe(true);
    expect(screen.getByText('custom_provider_preset')).toBeDefined();

    fireEvent.input(screen.getByPlaceholderText('my-project'), { target: { value: 'my-app' } });
    fireEvent.input(screen.getByPlaceholderText('~/projects/my-project'), { target: { value: '~/projects/my-app' } });
    fireEvent.click(screen.getByRole('button', { name: /start/i }));

    expect(ws.sendSessionCommand).toHaveBeenCalledWith('start', expect.objectContaining({
      agentType: 'qwen',
      ccPreset: 'MiniMax',
      requestedModel: 'MiniMax-M2.7',
      thinking: 'high',
    }));
    expect(ws.sendSessionCommand).not.toHaveBeenCalledWith('start', expect.objectContaining({
      agentType: 'custom-provider-sdk',
    }));
  });

  it('shows a toast when qwen preset JSON is copied to the clipboard', async () => {
    const clipboardWriteText = vi.fn().mockResolvedValue(undefined);
    Object.defineProperty(navigator, 'clipboard', {
      configurable: true,
      value: { writeText: clipboardWriteText },
    });
    const onToast = vi.fn();
    const ws = makeWs();
    ws.onMessage.mockImplementation((handler: (msg: unknown) => void) => {
      handler({
        type: 'cc.presets.list_response',
        presets: [
          {
            name: 'MiniMax',
            env: { ANTHROPIC_MODEL: 'MiniMax-M2.7' },
            defaultModel: 'MiniMax-M2.7',
          },
        ],
      });
      return () => {};
    });

    render(
      <NewSessionDialog
        ws={ws as any}
        onClose={vi.fn()}
        onSessionStarted={vi.fn()}
        isProviderConnected={() => false}
        onToast={onToast}
      />,
    );

    const agentTypeSelect = screen.getAllByRole('combobox')[0] as HTMLSelectElement;
    agentTypeSelect.value = 'qwen';
    fireEvent.input(agentTypeSelect, { target: { value: agentTypeSelect.value } });
    await waitFor(() => expect(screen.getByText('compatible_api_via_qwen')).toBeDefined());

    fireEvent.click(screen.getByText('api_provider_add_edit'));
    fireEvent.click(screen.getByRole('button', { name: 'api_provider_export_json' }));

    await waitFor(() => {
      expect(clipboardWriteText).toHaveBeenCalledOnce();
    });
    expect(JSON.parse(clipboardWriteText.mock.calls[0][0])).toMatchObject({ name: 'MiniMax' });
    expect(onToast).toHaveBeenCalledWith('api_provider_export_success');
  });

  it('saves qwen presets with the new default env template', async () => {
    const ws = makeWs();
    render(<NewSessionDialog ws={ws as any} onClose={vi.fn()} onSessionStarted={vi.fn()} isProviderConnected={() => false} />);

    const agentTypeSelect = screen.getAllByRole('combobox')[0] as HTMLSelectElement;
    agentTypeSelect.value = 'qwen';
    fireEvent.input(agentTypeSelect, { target: { value: agentTypeSelect.value } });
    await waitFor(() => expect(screen.getByText('compatible_api_via_qwen')).toBeDefined());

    fireEvent.click(screen.getByText('api_provider_add_edit'));
    fireEvent.input(screen.getByPlaceholderText('e.g. MiniMax'), { target: { value: 'MiniMax' } });
    fireEvent.click(screen.getByRole('button', { name: /save preset/i }));

    expect(ws.send).toHaveBeenCalledWith(expect.objectContaining({
      type: 'cc.presets.save',
      requestId: expect.any(String),
      presets: [
        expect.objectContaining({
          name: 'MiniMax',
          transportMode: 'qwen-compatible-api',
          authType: 'anthropic',
          defaultModel: 'MiniMax-M2.7',
          env: expect.objectContaining({
            ANTHROPIC_BASE_URL: 'https://api.minimax.io/anthropic',
            ANTHROPIC_MODEL: 'MiniMax-M2.7',
            API_TIMEOUT_MS: '3000000',
            CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: '1',
            CLAUDE_CODE_ATTRIBUTION_HEADER: '0',
          }),
        }),
      ],
    }));
  });

  it('keeps the preset env model authoritative for qwen after discovery', async () => {
    const ws = makeWs();
    render(<NewSessionDialog ws={ws as any} onClose={vi.fn()} onSessionStarted={vi.fn()} isProviderConnected={() => false} />);

    const agentTypeSelect = screen.getAllByRole('combobox')[0] as HTMLSelectElement;
    fireEvent.input(agentTypeSelect, { target: { value: 'qwen' } });
    fireEvent.click(screen.getByText('api_provider_add_edit'));
    fireEvent.input(screen.getByPlaceholderText('e.g. MiniMax'), { target: { value: 'MiniMax' } });
    fireEvent.input(screen.getByPlaceholderText('your-api-key'), { target: { value: 'secret' } });
    fireEvent.click(screen.getByRole('button', { name: /discover models/i }));
    act(() => ws.emit({
      type: 'cc.presets.discover_models_response',
      ok: true,
      presetName: 'MiniMax',
      preset: {
        name: 'MiniMax',
        env: {
          ANTHROPIC_BASE_URL: 'https://api.minimax.io/anthropic',
          ANTHROPIC_AUTH_TOKEN: 'secret',
          ANTHROPIC_MODEL: 'MiniMax-M2.7',
        },
        defaultModel: 'MiniMax-Text-01',
        availableModels: [{ id: 'MiniMax-M2.7' }, { id: 'MiniMax-Text-01' }],
      },
    }));

    fireEvent.input(screen.getByPlaceholderText('my-project'), { target: { value: 'my-app' } });
    fireEvent.input(screen.getByPlaceholderText('~/projects/my-project'), { target: { value: '~/projects/my-app' } });
    fireEvent.click(screen.getByRole('button', { name: /start/i }));

    await waitFor(() => {
      expect(ws.sendSessionCommand).toHaveBeenCalledWith('start', expect.objectContaining({
        agentType: 'qwen',
        ccPreset: 'MiniMax',
        requestedModel: 'MiniMax-M2.7',
      }));
    });
  });

  it('includes thinking level when starting qwen', async () => {
    const ws = makeWs();
    render(<NewSessionDialog ws={ws as any} onClose={vi.fn()} onSessionStarted={vi.fn()} isProviderConnected={() => false} />);

    fireEvent.input(screen.getByPlaceholderText('my-project'), { target: { value: 'my-app' } });
    fireEvent.input(screen.getByPlaceholderText('~/projects/my-project'), { target: { value: '~/projects/my-app' } });
    const agentTypeSelect = screen.getAllByRole('combobox')[0] as HTMLSelectElement;
    agentTypeSelect.value = 'qwen';
    fireEvent.input(agentTypeSelect, { target: { value: agentTypeSelect.value } });
    const selects = screen.getAllByRole('combobox') as HTMLSelectElement[];
    fireEvent.input(selects[1], { target: { value: 'high' } });
    fireEvent.click(screen.getByRole('button', { name: /start/i }));

    expect(ws.sendSessionCommand).toHaveBeenCalledWith('start', expect.objectContaining({
      agentType: 'qwen',
      thinking: 'high',
    }));
  });

  it('passes requestedModel when starting copilot-sdk', async () => {
    const ws = makeWs();
    render(<NewSessionDialog ws={ws as any} onClose={vi.fn()} onSessionStarted={vi.fn()} isProviderConnected={() => false} />);

    fireEvent.input(screen.getByPlaceholderText('my-project'), { target: { value: 'my-app' } });
    fireEvent.input(screen.getByPlaceholderText('~/projects/my-project'), { target: { value: '~/projects/my-app' } });
    const agentTypeSelect = screen.getAllByRole('combobox')[0] as HTMLSelectElement;
    fireEvent.input(agentTypeSelect, { target: { value: 'copilot-sdk' } });
    await waitFor(() => expect(screen.getAllByRole('combobox').length).toBeGreaterThanOrEqual(3));
    const selects = screen.getAllByRole('combobox') as HTMLSelectElement[];
    fireEvent.input(selects[2], { target: { value: 'gpt-5.4-mini' } });
    fireEvent.click(screen.getByRole('button', { name: /start/i }));

    expect(ws.sendSessionCommand).toHaveBeenCalledWith('start', expect.objectContaining({
      agentType: 'copilot-sdk',
      requestedModel: 'gpt-5.4-mini',
      thinking: 'high',
    }));
  });

  it('passes requestedModel when starting cursor-headless', async () => {
    const ws = makeWs();
    render(<NewSessionDialog ws={ws as any} onClose={vi.fn()} onSessionStarted={vi.fn()} isProviderConnected={() => false} />);

    fireEvent.input(screen.getByPlaceholderText('my-project'), { target: { value: 'my-app' } });
    fireEvent.input(screen.getByPlaceholderText('~/projects/my-project'), { target: { value: '~/projects/my-app' } });
    const agentTypeSelect = screen.getAllByRole('combobox')[0] as HTMLSelectElement;
    fireEvent.input(agentTypeSelect, { target: { value: 'cursor-headless' } });
    await waitFor(() => expect(screen.getAllByRole('combobox').length).toBeGreaterThanOrEqual(2));
    const selects = screen.getAllByRole('combobox') as HTMLSelectElement[];
    fireEvent.input(selects[1], { target: { value: 'gpt-5.2' } });
    fireEvent.click(screen.getByRole('button', { name: /start/i }));

    expect(ws.sendSessionCommand).toHaveBeenCalledWith('start', expect.objectContaining({
      agentType: 'cursor-headless',
      requestedModel: 'gpt-5.2',
    }));
  });

  it('keeps auto in gemini-sdk options when dynamic models are discovered', async () => {
    const ws = makeWs();
    render(<NewSessionDialog ws={ws as any} onClose={vi.fn()} onSessionStarted={vi.fn()} isProviderConnected={() => false} />);

    fireEvent.input(screen.getByPlaceholderText('my-project'), { target: { value: 'my-app' } });
    fireEvent.input(screen.getByPlaceholderText('~/projects/my-project'), { target: { value: '~/projects/my-app' } });
    const agentTypeSelect = screen.getAllByRole('combobox')[0] as HTMLSelectElement;
    agentTypeSelect.value = 'gemini-sdk';
    fireEvent.input(agentTypeSelect, { target: { value: 'gemini-sdk' } });

    await waitFor(() => {
      expect(ws.send.mock.calls.some((call) => (
        call[0]?.type === 'transport.list_models' && call[0]?.agentType === 'gemini-sdk'
      ))).toBe(true);
    });
    const request = ws.send.mock.calls.find((call) => (
      call[0]?.type === 'transport.list_models' && call[0]?.agentType === 'gemini-sdk'
    ))?.[0];
    expect(request).toMatchObject({ type: 'transport.list_models', agentType: 'gemini-sdk' });
    act(() => ws.emit({
      type: 'transport.models_response',
      agentType: 'gemini-sdk',
      requestId: request?.requestId,
      models: [
        { id: 'gemini-2.5-pro', name: 'Gemini 2.5 Pro' },
        { id: 'gemini-2.5-flash', name: 'Gemini 2.5 Flash' },
      ],
    }));

    await waitFor(() => expect(screen.getByRole('option', { name: 'auto' })).toBeDefined());
    const selects = screen.getAllByRole('combobox') as HTMLSelectElement[];
    fireEvent.input(selects[1], { target: { value: 'auto' } });
    fireEvent.click(screen.getByRole('button', { name: /start/i }));

    expect(ws.sendSessionCommand).toHaveBeenCalledWith('start', expect.objectContaining({
      agentType: 'gemini-sdk',
      requestedModel: 'auto',
    }));
  });

  it('uses dynamically discovered kimi-sdk models when starting a session', async () => {
    const ws = makeWs();
    render(<NewSessionDialog ws={ws as any} onClose={vi.fn()} onSessionStarted={vi.fn()} isProviderConnected={() => false} />);

    fireEvent.input(screen.getByPlaceholderText('my-project'), { target: { value: 'my-app' } });
    fireEvent.input(screen.getByPlaceholderText('~/projects/my-project'), { target: { value: '~/projects/my-app' } });
    const agentTypeSelect = screen.getAllByRole('combobox')[0] as HTMLSelectElement;
    agentTypeSelect.value = 'kimi-sdk';
    fireEvent.input(agentTypeSelect, { target: { value: 'kimi-sdk' } });

    await waitFor(() => {
      expect(ws.send.mock.calls.some((call) => (
        call[0]?.type === 'transport.list_models' && call[0]?.agentType === 'kimi-sdk'
      ))).toBe(true);
    });
    const request = ws.send.mock.calls.find((call) => (
      call[0]?.type === 'transport.list_models' && call[0]?.agentType === 'kimi-sdk'
    ))?.[0];
    act(() => ws.emit({
      type: 'transport.models_response',
      agentType: 'kimi-sdk',
      requestId: request?.requestId,
      models: [
        { id: 'moonshot-v1-auto', name: 'Moonshot Auto' },
        { id: 'moonshot-v1-auto,thinking', name: 'Moonshot Auto Thinking' },
      ],
    }));

    await waitFor(() => expect(screen.getByRole('option', { name: 'moonshot-v1-auto,thinking' })).toBeDefined());
    const selects = screen.getAllByRole('combobox') as HTMLSelectElement[];
    fireEvent.input(selects[1], { target: { value: 'moonshot-v1-auto,thinking' } });
    fireEvent.click(screen.getByRole('button', { name: /start/i }));

    expect(ws.sendSessionCommand).toHaveBeenCalledWith('start', expect.objectContaining({
      agentType: 'kimi-sdk',
      requestedModel: 'moonshot-v1-auto,thinking',
    }));
  });
});
