import React, { act } from 'react';
import { createRoot } from 'react-dom/client';

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

import { RuntimeProviderManagementPanelView } from '../../../../src/features/runtime-provider-management/renderer/ui/RuntimeProviderManagementPanelView';

import type {
  RuntimeProviderManagementActions,
  RuntimeProviderManagementState,
} from '../../../../src/features/runtime-provider-management/renderer/hooks/useRuntimeProviderManagement';

function createState(
  overrides: Partial<RuntimeProviderManagementState> = {}
): RuntimeProviderManagementState {
  return {
    view: {
      runtimeId: 'opencode',
      title: 'OpenCode',
      runtime: {
        state: 'ready',
        cliPath: '/usr/local/bin/opencode',
        version: '1.14.24',
        managedProfile: 'active',
        localAuth: 'synced',
      },
      providers: [
        {
          providerId: 'openrouter',
          displayName: 'OpenRouter',
          state: 'available',
          ownership: [],
          recommended: true,
          modelCount: 4,
          defaultModelId: null,
          authMethods: ['api'],
          actions: [
            {
              id: 'connect',
              label: 'Connect',
              enabled: true,
              disabledReason: null,
              requiresSecret: true,
              ownershipScope: 'managed',
            },
          ],
          detail: null,
        },
      ],
      defaultModel: null,
      fallbackModel: null,
      diagnostics: [],
    },
    providers: [],
    selectedProviderId: 'openrouter',
    providerQuery: '',
    directoryLoading: false,
    directoryRefreshing: false,
    directoryError: null,
    directoryErrorDiagnostics: null,
    directoryEntries: [],
    directoryTotalCount: null,
    directoryNextCursor: null,
    directoryLoaded: false,
    directorySelectedProviderId: null,
    directorySupported: true,
    activeFormProviderId: null,
    setupForm: null,
    setupFormLoading: false,
    setupFormError: null,
    setupFormErrorDiagnostics: null,
    setupSubmitError: null,
    setupSubmitErrorDiagnostics: null,
    setupMetadata: {},
    apiKeyValue: '',
    modelPickerProviderId: null,
    modelPickerMode: null,
    modelQuery: '',
    models: [],
    modelsLoading: false,
    modelsError: null,
    modelsErrorDiagnostics: null,
    selectedModelId: null,
    testingModelIds: [],
    savingDefaultModelId: null,
    modelResults: {},
    loading: false,
    savingProviderId: null,
    error: null,
    errorDiagnostics: null,
    successMessage: null,
    ...overrides,
  };
}

function createActions(): RuntimeProviderManagementActions {
  return {
    refresh: vi.fn(() => Promise.resolve()),
    selectProvider: vi.fn(),
    setProviderQuery: vi.fn(),
    loadMoreDirectory: vi.fn(() => Promise.resolve()),
    refreshDirectory: vi.fn(() => Promise.resolve()),
    selectDirectoryProvider: vi.fn(),
    searchAllProviders: vi.fn(),
    startConnect: vi.fn(),
    cancelConnect: vi.fn(),
    setApiKeyValue: vi.fn(),
    setSetupMetadataValue: vi.fn(),
    submitConnect: vi.fn(() => Promise.resolve()),
    forgetProvider: vi.fn(() => Promise.resolve()),
    openModelPicker: vi.fn(),
    closeModelPicker: vi.fn(),
    setModelQuery: vi.fn(),
    selectModel: vi.fn(),
    useModelForNewTeams: vi.fn(),
    testModel: vi.fn(() => Promise.resolve()),
    setDefaultModel: vi.fn(() => Promise.resolve()),
  };
}

function setInputValue(input: HTMLInputElement, value: string): void {
  const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')?.set;
  if (!setter) {
    throw new Error('HTMLInputElement value setter not found');
  }

  setter.call(input, value);
  input.dispatchEvent(new Event('input', { bubbles: true }));
}

async function selectOpenCodeTab(host: HTMLElement, label: 'Models' | 'Providers'): Promise<void> {
  const trigger = Array.from(host.querySelectorAll<HTMLButtonElement>('[role="tab"]')).find((button) =>
    button.textContent?.trim().startsWith(label)
  );
  if (!trigger) {
    throw new Error(`${label} tab trigger not found`);
  }

  await act(async () => {
    trigger.dispatchEvent(new MouseEvent('mousedown', { bubbles: true, button: 0 }));
    await Promise.resolve();
  });
}

describe('RuntimeProviderManagementPanelView', () => {
  beforeEach(() => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
  });

  afterEach(() => {
    document.body.innerHTML = '';
    vi.unstubAllGlobals();
  });

  it('renders an explicit loading state while the managed OpenCode view is loading', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const actions = createActions();

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({
            view: null,
            providers: [],
            loading: true,
          }),
          actions,
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('Checking runtime');
    expect(host.textContent).toContain('Loading managed OpenCode runtime');
    expect(host.textContent).toContain('Loading OpenCode providers');
    expect(host.querySelector('[data-testid="runtime-provider-model-loading-skeleton"]')).toBeNull();

    await selectOpenCodeTab(host, 'Models');

    expect(host.textContent).toContain('Loading OpenCode model routes');
    expect(
      host.querySelector('[data-testid="runtime-provider-model-loading-skeleton"]')
    ).not.toBeNull();
    expect(host.querySelectorAll('.skeleton-shimmer').length).toBeGreaterThanOrEqual(8);
    expect(host.textContent).toContain('Checking...');
    const refreshButton = Array.from(host.querySelectorAll('button')).find((button) =>
      button.textContent?.includes('Checking...')
    );
    expect(refreshButton?.disabled).toBe(true);

    expect(host.textContent).not.toContain('No launchable OpenCode model routes were reported yet');
  });

  it('renders runtime command errors with a readable headline and multiline details', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const message = [
      'OpenCode provider settings could not read the runtime response.',
      'Expected a JSON object from the Agent Teams runtime provider command.',
      'Resolved runtime binary: /opt/homebrew/bin/opencode',
      'Command: /opt/homebrew/bin/opencode runtime providers view --runtime opencode --json --compact',
      'stdout preview:',
      'Commands:',
      '  opencode providers',
    ].join('\n');

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({ error: message }),
          actions: createActions(),
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    const alert = host.querySelector<HTMLElement>('[data-testid="runtime-provider-error"]');
    const details = alert?.querySelector('pre');

    expect(alert?.getAttribute('role')).toBe('alert');
    expect(alert?.textContent).toContain(
      'OpenCode provider settings could not read the runtime response.'
    );
    expect(details?.textContent).toContain('Resolved runtime binary: /opt/homebrew/bin/opencode');
    expect(details?.textContent).toContain('  opencode providers');
    expect(details?.className).toContain('whitespace-pre-wrap');
    expect(details?.className).toContain('font-mono');
  });

  it('shows the Windows administrator hint only for OpenCode node_modules symlink EPERM errors', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const symlinkError = [
      'Runtime provider management command failed unexpectedly:',
      "EPERM: operation not permitted, symlink 'C:\\Users\\ben\\AppData\\Local\\claude-multimodel-nodejs\\Cache\\opencode\\shared-cache\\config-node_modules'",
      "-> 'C:\\Users\\ben\\AppData\\Local\\claude-multimodel-nodejs\\Data\\opencode\\profiles\\abc123\\config\\opencode\\node_modules'",
    ].join(' ');

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({ error: symlinkError }),
          actions: createActions(),
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('Windows: run Agent Teams AI as Administrator');

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({
            error: 'EPERM: operation not permitted, mkdir C:\\Program Files\\locked-project',
          }),
          actions: createActions(),
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).not.toContain('Windows: run Agent Teams AI as Administrator');
  });

  it('copies fallback error text when structured diagnostics are unavailable', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const writeText = vi.fn((_text: string) => Promise.resolve());
    const clipboardDescriptor = Object.getOwnPropertyDescriptor(navigator, 'clipboard');
    Object.defineProperty(navigator, 'clipboard', {
      configurable: true,
      value: { writeText },
    });

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({
            error: 'Runtime provider crashed\nstderr preview:\nmissing bun',
            errorDiagnostics: null,
          }),
          actions: createActions(),
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    await act(async () => {
      Array.from(host.querySelectorAll('button'))
        .find((button) => button.textContent?.includes('Copy diagnostics'))
        ?.click();
      await Promise.resolve();
    });

    expect(writeText).toHaveBeenCalledWith(
      'OpenCode provider settings diagnostics\n\nMessage:\nRuntime provider crashed\nstderr preview:\nmissing bun'
    );
    if (clipboardDescriptor) {
      Object.defineProperty(navigator, 'clipboard', clipboardDescriptor);
    } else {
      Reflect.deleteProperty(navigator, 'clipboard');
    }
  });

  it('copies diagnostics with the selection fallback when clipboard API is unavailable', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const clipboardDescriptor = Object.getOwnPropertyDescriptor(navigator, 'clipboard');
    const execCommandDescriptor = Object.getOwnPropertyDescriptor(document, 'execCommand');
    const execCommand = vi.fn(() => true);
    Object.defineProperty(navigator, 'clipboard', {
      configurable: true,
      value: undefined,
    });
    Object.defineProperty(document, 'execCommand', {
      configurable: true,
      value: execCommand,
    });

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({
            error: 'Runtime provider crashed\nstderr preview:\nmissing bun',
            errorDiagnostics: null,
          }),
          actions: createActions(),
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    await act(async () => {
      Array.from(host.querySelectorAll('button'))
        .find((button) => button.textContent?.includes('Copy diagnostics'))
        ?.click();
      await Promise.resolve();
    });

    expect(execCommand).toHaveBeenCalledWith('copy');
    expect(host.textContent).toContain('Copied');
    expect(document.querySelector('textarea')).toBeNull();
    if (clipboardDescriptor) {
      Object.defineProperty(navigator, 'clipboard', clipboardDescriptor);
    } else {
      Reflect.deleteProperty(navigator, 'clipboard');
    }
    if (execCommandDescriptor) {
      Object.defineProperty(document, 'execCommand', execCommandDescriptor);
    } else {
      Reflect.deleteProperty(document, 'execCommand');
    }
  });

  it('renders structured runtime diagnostics and copies the full redacted report', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const writeText = vi.fn((_text: string) => Promise.resolve());
    const clipboardDescriptor = Object.getOwnPropertyDescriptor(navigator, 'clipboard');
    Object.defineProperty(navigator, 'clipboard', {
      configurable: true,
      value: { writeText },
    });

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({
            error: 'OpenCode provider settings could not read the runtime response.',
            errorDiagnostics: {
              errorCode: 'runtime-unhealthy',
              summary: 'OpenCode provider settings could not read the runtime response.',
              likelyCause:
                'The app is launching the OpenCode CLI itself instead of the Agent Teams runtime.',
              binaryPath: '/opt/homebrew/bin/opencode',
              command:
                '/opt/homebrew/bin/opencode runtime providers view --runtime opencode --json --compact',
              projectPath: '/Users/test/project',
              exitCode: 1,
              stderrPreview: 'Command failed before JSON',
              stdoutPreview: 'Commands:\n  opencode providers',
              hints: [
                'Check CLAUDE_AGENT_TEAMS_ORCHESTRATOR_CLI_PATH and CLAUDE_CLI_PATH.',
                'Those environment variables must not point to opencode.',
              ],
            },
          }),
          actions: createActions(),
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('Likely cause');
    expect(host.textContent).toContain('/opt/homebrew/bin/opencode');
    expect(host.textContent).toContain('Command failed before JSON');
    expect(
      host.querySelector('[data-testid="runtime-provider-error-stderr-preview"]')?.textContent
    ).toContain('stderr preview');
    expect(
      host.querySelector('[data-testid="runtime-provider-error-stdout-preview"]')?.textContent
    ).toContain('opencode providers');

    await act(async () => {
      Array.from(host.querySelectorAll('button'))
        .find((button) => button.textContent?.includes('Copy diagnostics'))
        ?.click();
      await Promise.resolve();
    });

    expect(writeText).toHaveBeenCalledTimes(1);
    expect(writeText.mock.calls[0][0]).toContain('OpenCode provider settings diagnostics');
    expect(writeText.mock.calls[0][0]).toContain('Error code: runtime-unhealthy');
    expect(writeText.mock.calls[0][0]).toContain('Resolved runtime binary: /opt/homebrew/bin/opencode');
    expect(writeText.mock.calls[0][0]).toContain('stderr preview:');
    expect(writeText.mock.calls[0][0]).toContain('stdout preview:');
    expect(host.textContent).toContain('Copied');
    if (clipboardDescriptor) {
      Object.defineProperty(navigator, 'clipboard', clipboardDescriptor);
    } else {
      Reflect.deleteProperty(navigator, 'clipboard');
    }
  });

  it('does not activate a provider row when copying model diagnostics', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const writeText = vi.fn((_text: string) => Promise.resolve());
    const clipboardDescriptor = Object.getOwnPropertyDescriptor(navigator, 'clipboard');
    Object.defineProperty(navigator, 'clipboard', {
      configurable: true,
      value: { writeText },
    });
    const actions = createActions();
    const base = createState();
    const provider = {
      ...base.view!.providers[0],
      state: 'connected' as const,
      modelCount: 2,
      actions: [
        {
          id: 'test' as const,
          label: 'Test',
          enabled: true,
          disabledReason: null,
          requiresSecret: false,
          ownershipScope: 'runtime' as const,
        },
      ],
    };

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({
            view: {
              ...base.view!,
              providers: [provider],
            },
            providers: [provider],
            selectedProviderId: provider.providerId,
            modelPickerProviderId: provider.providerId,
            modelPickerMode: 'use',
            modelsError: 'Model list failed',
            modelsErrorDiagnostics: {
              summary: 'Model list failed',
              likelyCause: 'The runtime returned a malformed models response.',
              binaryPath: '/repo/cli-dev',
              command: '/repo/cli-dev runtime providers models --runtime opencode',
              projectPath: '/Users/test/project',
              exitCode: 1,
              stderrPreview: 'bad models payload',
              stdoutPreview: null,
              hints: ['Retry after refreshing the runtime.'],
            },
          }),
          actions,
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    await act(async () => {
      Array.from(host.querySelectorAll('button'))
        .find((button) => button.textContent?.includes('Copy diagnostics'))
        ?.click();
      await Promise.resolve();
    });

    expect(writeText).toHaveBeenCalledTimes(1);
    expect(actions.selectProvider).not.toHaveBeenCalled();
    expect(actions.startConnect).not.toHaveBeenCalled();
    if (clipboardDescriptor) {
      Object.defineProperty(navigator, 'clipboard', clipboardDescriptor);
    } else {
      Reflect.deleteProperty(navigator, 'clipboard');
    }
  });

  it('renders structured diagnostics in provider form and model picker errors', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const provider = {
      ...createState().view!.providers[0],
      state: 'connected' as const,
      modelCount: 4,
      actions: [
        {
          id: 'test' as const,
          label: 'Test',
          enabled: true,
          disabledReason: null,
          requiresSecret: false,
          ownershipScope: 'runtime' as const,
        },
      ],
    };

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({
            providers: [provider],
            selectedProviderId: provider.providerId,
            activeFormProviderId: provider.providerId,
            modelPickerProviderId: provider.providerId,
            modelPickerMode: 'use',
            setupSubmitError: 'Provider connect failed before JSON.',
            setupSubmitErrorDiagnostics: {
              summary: 'Provider connect failed before JSON.',
              likelyCause: 'The runtime command printed CLI help instead of JSON.',
              binaryPath: '/opt/homebrew/bin/opencode',
              command: '/opt/homebrew/bin/opencode runtime providers connect',
              projectPath: null,
              exitCode: 1,
              stderrPreview: 'unknown command',
              stdoutPreview: 'Commands:\n  opencode providers',
              hints: ['Check the resolved runtime binary.'],
            },
            modelsError: 'Provider models failed before JSON.',
            modelsErrorDiagnostics: {
              summary: 'Provider models failed before JSON.',
              likelyCause: 'The runtime command printed CLI help instead of JSON.',
              binaryPath: '/opt/homebrew/bin/opencode',
              command: '/opt/homebrew/bin/opencode runtime providers models',
              projectPath: null,
              exitCode: 1,
              stderrPreview: 'unknown command',
              stdoutPreview: 'Commands:\n  opencode providers',
              hints: ['Check the resolved runtime binary.'],
            },
          }),
          actions: createActions(),
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    expect(
      host.querySelector('[data-testid="runtime-provider-setup-submit-error"]')?.textContent
    ).toContain('Provider connect failed before JSON.');
    expect(
      host.querySelector('[data-testid="runtime-provider-setup-submit-error"]')?.textContent
    ).toContain('/opt/homebrew/bin/opencode');
    expect(host.querySelector('[data-testid="runtime-provider-models-error"]')?.textContent).toContain(
      'Provider models failed before JSON.'
    );
    expect(host.querySelector('[data-testid="runtime-provider-models-error"]')?.textContent).toContain(
      'opencode providers'
    );
  });

  it('renders provider directory errors with preserved multiline details', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const message = [
      'OpenCode provider settings could not read the runtime response.',
      'stderr preview:',
      'runtime crashed before JSON',
    ].join('\n');

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({
            directoryError: message,
            directoryLoaded: true,
          }),
          actions: createActions(),
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    const alert = host.querySelector<HTMLElement>(
      '[data-testid="runtime-provider-directory-error"]'
    );
    const details = alert?.querySelector('pre');

    expect(alert?.getAttribute('role')).toBe('alert');
    expect(details?.textContent).toContain('stderr preview:');
    expect(details?.textContent).toContain('runtime crashed before JSON');
    expect(details?.className).toContain('whitespace-pre-wrap');
  });

  it('keeps project context out of the runtime summary and labels it as validation context', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({
            view: {
              ...createState().view!,
              configuredModels: [
                {
                  providerId: 'llama.cpp',
                  modelId: 'llama.cpp/qwen-test:0.5b',
                  displayName: 'qwen-test:0.5b',
                  sourceLabel: 'llama.cpp',
                  free: false,
                  default: false,
                  availability: 'available',
                  accessKind: 'verified',
                  routeKind: 'configured_local',
                  proofState: 'verified',
                  requiresExecutionProof: false,
                  accessReason: null,
                },
              ],
            },
          }),
          actions: createActions(),
          disabled: false,
          projectPath: '/Users/belief/dev/projects/321',
        })
      );
      await Promise.resolve();
    });

    await selectOpenCodeTab(host, 'Models');

    expect(host.textContent).toContain('OpenCode defaults');
    expect(host.textContent).toContain('Validation context');
    expect(host.textContent).toContain('Tests use 321. Default applies unless');
    expect(host.textContent).not.toContain('Project context: 321');
    expect(host.textContent).not.toContain('Current context: 321');
    expect(host.textContent).not.toContain('Managing selected project profile');
    expect(host.textContent).not.toContain('/Users/belief/dev/projects/321');
  });

  it('renders configured OpenCode model routes with local proof actions', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const actions = createActions();
    const configuredModel = {
      providerId: 'llama.cpp',
      modelId: 'llama.cpp/qwen-test:0.5b',
      displayName: 'qwen-test:0.5b',
      sourceLabel: 'llama.cpp',
      free: false,
      default: false,
      availability: 'untested' as const,
      accessKind: 'configured_authless' as const,
      routeKind: 'configured_local' as const,
      proofState: 'needs_probe' as const,
      requiresExecutionProof: true,
      accessReason: 'Execution proof required',
    };

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({
            view: {
              ...createState().view!,
              configuredModels: [configuredModel],
            },
            selectedModelId: 'llama.cpp/qwen-test:0.5b',
          }),
          actions,
          disabled: false,
          projectPath: '/tmp/project',
        })
      );
      await Promise.resolve();
    });

    await selectOpenCodeTab(host, 'Models');

    const row = host.querySelector<HTMLElement>(
      '[data-testid="configured-opencode-model-row-llama.cpp/qwen-test:0.5b"]'
    );
    expect(host.textContent).toContain('OpenCode model routes');
    expect(host.textContent).toContain('Known routes from OpenCode config');
    expect(row?.textContent).toContain('local');
    expect(row?.textContent).toContain('known route');
    expect(row?.textContent).toContain('needs test');

    const buttons = Array.from(row?.querySelectorAll('button') ?? []);
    await act(async () => {
      buttons.find((button) => button.textContent?.includes('Test'))?.click();
      await Promise.resolve();
    });
    await act(async () => {
      buttons.find((button) => button.textContent?.includes('Save for team picker'))?.click();
      await Promise.resolve();
    });
    await act(async () => {
      buttons.find((button) => button.textContent?.includes('Set all-projects default'))?.click();
      await Promise.resolve();
    });

    expect(actions.testModel).toHaveBeenCalledWith('llama.cpp', 'llama.cpp/qwen-test:0.5b');
    expect(actions.useModelForNewTeams).toHaveBeenCalledWith('llama.cpp/qwen-test:0.5b');
    expect(actions.setDefaultModel).toHaveBeenCalledWith(
      'llama.cpp',
      'llama.cpp/qwen-test:0.5b',
      'all_projects'
    );
  });

  it('can set an all-projects OpenCode default from the model scope controls', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const actions = createActions();
    const configuredModel = {
      providerId: 'llama.cpp',
      modelId: 'llama.cpp/qwen-test:0.5b',
      displayName: 'qwen-test:0.5b',
      sourceLabel: 'llama.cpp',
      free: false,
      default: false,
      availability: 'available' as const,
      accessKind: 'verified' as const,
      routeKind: 'configured_local' as const,
      proofState: 'verified' as const,
      requiresExecutionProof: false,
      accessReason: null,
    };

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({
            view: {
              ...createState().view!,
              configuredModels: [configuredModel],
            },
          }),
          actions,
          disabled: false,
          projectPath: '/tmp/project-a',
        })
      );
      await Promise.resolve();
    });

    await selectOpenCodeTab(host, 'Models');

    await act(async () => {
      Array.from(host.querySelectorAll('button'))
        .find((button) => button.textContent?.includes('Set all-projects default'))
        ?.click();
      await Promise.resolve();
    });

    expect(host.textContent).toContain(
      'Default for every project that does not have its own OpenCode override'
    );
    expect(host.textContent).toContain('Validation context');
    expect(actions.setDefaultModel).toHaveBeenCalledWith(
      'llama.cpp',
      'llama.cpp/qwen-test:0.5b',
      'all_projects'
    );
  });

  it('filters launchable OpenCode model routes by route text', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const localModel = {
      providerId: 'llama.cpp',
      modelId: 'llama.cpp/qwen-test:0.5b',
      displayName: 'qwen-test:0.5b',
      sourceLabel: 'llama.cpp',
      free: false,
      default: false,
      availability: 'available' as const,
      accessKind: 'verified' as const,
      routeKind: 'configured_local' as const,
      proofState: 'verified' as const,
      requiresExecutionProof: false,
      accessReason: null,
    };
    const freeModel = {
      providerId: 'opencode',
      modelId: 'opencode/big-pickle',
      displayName: 'big-pickle',
      sourceLabel: 'OpenCode',
      free: true,
      default: false,
      availability: 'available' as const,
      accessKind: 'builtin_free' as const,
      routeKind: 'builtin_free' as const,
      proofState: 'not_required' as const,
      requiresExecutionProof: false,
      accessReason: null,
    };

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({
            view: {
              ...createState().view!,
              configuredModels: [localModel, freeModel],
            },
          }),
          actions: createActions(),
          disabled: false,
          projectPath: '/tmp/project-a',
        })
      );
      await Promise.resolve();
    });

    await selectOpenCodeTab(host, 'Models');

    const searchInput = host.querySelector<HTMLInputElement>(
      'input[placeholder="Search model routes"]'
    );
    expect(searchInput).not.toBeNull();
    expect(host.textContent).toContain('qwen-test:0.5b');
    expect(host.textContent).toContain('big-pickle');

    await act(async () => {
      setInputValue(searchInput!, 'pickle');
      await Promise.resolve();
    });

    expect(host.textContent).not.toContain('qwen-test:0.5b');
    expect(host.textContent).toContain('big-pickle');

    await act(async () => {
      setInputValue(searchInput!, 'missing-route');
      await Promise.resolve();
    });

    expect(host.textContent).toContain('No OpenCode model routes match');
    expect(host.textContent).toContain('missing-route');
  });

  it('opens providers first and keeps launchable routes in a separate tab', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const baseState = createState();
    const configuredModel = {
      providerId: 'llama.cpp',
      modelId: 'llama.cpp/qwen-test:0.5b',
      displayName: 'qwen-test:0.5b',
      sourceLabel: 'llama.cpp',
      free: false,
      default: false,
      availability: 'untested' as const,
      accessKind: 'configured_authless' as const,
      routeKind: 'configured_local' as const,
      proofState: 'needs_probe' as const,
      requiresExecutionProof: true,
      accessReason: 'Execution proof required',
    };

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({
            view: {
              ...baseState.view!,
              configuredModels: [configuredModel],
            },
            providers: baseState.view?.providers ?? [],
          }),
          actions: createActions(),
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('Providers');
    expect(host.querySelector('[data-testid="runtime-provider-row-openrouter"]')).not.toBeNull();
    expect(host.querySelector('[data-testid="configured-opencode-model-row-llama.cpp/qwen-test:0.5b"]')).toBeNull();

    await selectOpenCodeTab(host, 'Models');

    expect(host.textContent).toContain('OpenCode model routes');
    expect(host.textContent).toContain('llama.cpp/qwen-test:0.5b');
    expect(host.textContent).toContain(
      'Select a validation context above to enable Test and Set default'
    );
    expect(host.querySelector('[data-testid="runtime-provider-row-openrouter"]')).toBeNull();

    const row = host.querySelector<HTMLElement>(
      '[data-testid="configured-opencode-model-row-llama.cpp/qwen-test:0.5b"]'
    );
    const buttons = Array.from(row?.querySelectorAll('button') ?? []);
    expect(buttons.map((button) => [button.textContent?.trim(), button.disabled])).toEqual([
      ['Test', true],
      ['Save for team picker', false],
      ['Set all-projects default', true],
    ]);
    expect(
      Array.from(row?.querySelectorAll('[title]') ?? []).some(
        (element) =>
          element.getAttribute('title') ===
          'Select a project context before testing or saving OpenCode defaults.'
      )
    ).toBe(true);
  });

  it('shows unknown OpenCode defaults without enabling launch actions', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const actions = createActions();
    const unknownDefaultModel = {
      providerId: 'openrouter',
      modelId: 'openrouter/moonshotai/kimi-k2',
      displayName: 'moonshotai/kimi-k2',
      sourceLabel: 'OpenRouter',
      free: false,
      default: true,
      availability: 'untested' as const,
      accessKind: 'unknown_model' as const,
      routeKind: 'catalog_provider' as const,
      proofState: 'not_required' as const,
      requiresExecutionProof: false,
      accessReason: 'Model was not found in the live catalog',
    };

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({
            view: {
              ...createState().view!,
              configuredModels: [unknownDefaultModel],
            },
          }),
          actions,
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    await selectOpenCodeTab(host, 'Models');

    const row = host.querySelector<HTMLElement>(
      '[data-testid="configured-opencode-model-row-openrouter/moonshotai/kimi-k2"]'
    );
    expect(row?.textContent).toContain('unknown');
    expect(row?.textContent).toContain('default');

    const buttons = Array.from(row?.querySelectorAll('button') ?? []);
    expect(buttons.map((button) => button.disabled)).toEqual([true, true, true]);
    expect(
      Array.from(row?.querySelectorAll('[title]') ?? []).some(
        (element) =>
          element.getAttribute('title') ===
          'This model is the current OpenCode default, but it is not available in the live catalog yet.'
      )
    ).toBe(true);
    await act(async () => {
      buttons.forEach((button) => button.click());
      await Promise.resolve();
    });
    expect(actions.testModel).not.toHaveBeenCalled();
    expect(actions.useModelForNewTeams).not.toHaveBeenCalled();
    expect(actions.setDefaultModel).not.toHaveBeenCalled();
  });

  it('renders duplicate runtime diagnostics without React key warnings', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const actions = createActions();
    const baseState = createState();
    const consoleError = vi.spyOn(console, 'error').mockImplementation(() => undefined);

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({
            view: {
              ...baseState.view!,
              diagnostics: [
                'Unable to connect. Is the computer able to access the url?',
                'Unable to connect. Is the computer able to access the url?',
              ],
            },
            providers: baseState.view?.providers ?? [],
          }),
          actions,
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    const duplicateDiagnostics = host.textContent?.match(
      /Unable to connect\. Is the computer able to access the url\?/g
    );
    const duplicateKeyWarnings = consoleError.mock.calls.filter((call) =>
      call.some(
        (argument) =>
          typeof argument === 'string' &&
          argument.includes('Encountered two children with the same key')
      )
    );
    consoleError.mockRestore();

    expect(duplicateDiagnostics).toHaveLength(2);
    expect(duplicateKeyWarnings).toHaveLength(0);
  });

  it('renders duplicate structured diagnostic hints without React key warnings', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const consoleError = vi.spyOn(console, 'error').mockImplementation(() => undefined);

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({
            error: 'OpenCode provider settings are using the wrong runtime binary.',
            errorDiagnostics: {
              summary: 'OpenCode provider settings are using the wrong runtime binary.',
              likelyCause:
                'The app resolved the OpenCode CLI itself as the Agent Teams runtime binary.',
              binaryPath: '/opt/homebrew/bin/opencode',
              command:
                '/opt/homebrew/bin/opencode runtime providers view --runtime opencode --json --compact',
              projectPath: null,
              exitCode: null,
              stderrPreview: null,
              stdoutPreview: null,
              hints: [
                'Those environment variables must not point to opencode.',
                'Those environment variables must not point to opencode.',
              ],
            },
          }),
          actions: createActions(),
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    const duplicateHints = host.textContent?.match(
      /Those environment variables must not point to opencode\./g
    );
    const duplicateKeyWarnings = consoleError.mock.calls.filter((call) =>
      call.some(
        (argument) =>
          typeof argument === 'string' &&
          argument.includes('Encountered two children with the same key')
      )
    );
    consoleError.mockRestore();

    expect(duplicateHints).toHaveLength(2);
    expect(duplicateKeyWarnings).toHaveLength(0);
  });

  it('renders provider actions and opens API-key form state without exposing a raw secret', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const actions = createActions();
    const state = createState();

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: { ...state, providers: state.view?.providers ?? [] },
          actions,
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('OpenRouter');
    expect(host.textContent).toContain('4 models');
    expect(host.querySelector('[data-testid="runtime-provider-search"]')).not.toBeNull();
    expect(
      host.querySelector('[data-testid="runtime-provider-row-openrouter"]')?.className
    ).toContain('hover:bg-sky-400');

    await act(async () => {
      host
        .querySelector('[data-testid="runtime-provider-row-openrouter"]')
        ?.dispatchEvent(new MouseEvent('click', { bubbles: true }));
      await Promise.resolve();
    });

    expect(actions.startConnect).toHaveBeenCalledWith('openrouter');
    expect(actions.selectProvider).not.toHaveBeenCalled();

    vi.mocked(actions.startConnect).mockClear();

    await act(async () => {
      const connect = Array.from(host.querySelectorAll('button')).find((button) =>
        button.textContent?.includes('Connect')
      );
      connect?.dispatchEvent(new MouseEvent('click', { bubbles: true }));
      await Promise.resolve();
    });

    expect(actions.startConnect).toHaveBeenCalledWith('openrouter');

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: {
            ...state,
            providers: state.view?.providers ?? [],
            activeFormProviderId: 'openrouter',
            apiKeyValue: 'sk-secret-value',
            setupForm: {
              runtimeId: 'opencode',
              providerId: 'openrouter',
              displayName: 'OpenRouter',
              method: 'api',
              supported: true,
              title: 'Connect OpenRouter',
              description: null,
              submitLabel: 'Connect',
              disabledReason: null,
              source: 'curated',
              secret: {
                key: 'key',
                label: 'API key',
                placeholder: 'Paste API key',
                required: true,
              },
              prompts: [],
            },
          },
          actions,
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    expect(host.querySelector('input[type="password"]')).not.toBeNull();
    expect(host.textContent).not.toContain('sk-secret-value');
  });

  it('allows supported setup forms that do not require a secret to submit', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const actions = createActions();
    const state = createState();

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: {
            ...state,
            providers: state.view?.providers ?? [],
            activeFormProviderId: 'openrouter',
            setupForm: {
              runtimeId: 'opencode',
              providerId: 'openrouter',
              displayName: 'OpenRouter',
              method: 'oauth',
              supported: true,
              title: 'Connect OpenRouter',
              description: null,
              submitLabel: 'Connect',
              disabledReason: null,
              source: 'oauth',
              secret: null,
              prompts: [],
            },
          },
          actions,
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    const submitButton = Array.from(host.querySelectorAll('button'))
      .filter((button) => button.textContent?.trim() === 'Connect')
      .at(-1);
    expect(submitButton?.disabled).toBe(false);
  });

  it('renders multiple compact provider actions without hiding forget behind connect', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const actions = createActions();
    const provider = {
      ...createState().view!.providers[0],
      actions: [
        {
          id: 'connect' as const,
          label: 'Connect',
          enabled: true,
          disabledReason: null,
          requiresSecret: true,
          ownershipScope: 'managed' as const,
        },
        {
          id: 'forget' as const,
          label: 'Forget',
          enabled: true,
          disabledReason: null,
          requiresSecret: false,
          ownershipScope: 'managed' as const,
        },
      ],
    };

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({
            view: {
              ...createState().view!,
              providers: [provider],
            },
            providers: [provider],
          }),
          actions,
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    const buttons = Array.from(host.querySelectorAll('button'));
    expect(buttons.some((button) => button.textContent?.includes('Connect'))).toBe(true);
    expect(buttons.some((button) => button.textContent?.includes('Forget'))).toBe(true);

    await act(async () => {
      buttons
        .find((button) => button.textContent?.includes('Forget'))
        ?.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }));
      await Promise.resolve();
    });

    expect(actions.startConnect).not.toHaveBeenCalled();

    await act(async () => {
      buttons
        .find((button) => button.textContent?.includes('Forget'))
        ?.dispatchEvent(new MouseEvent('click', { bubbles: true }));
      await Promise.resolve();
    });

    expect(actions.forgetProvider).toHaveBeenCalledWith('openrouter');
    expect(actions.startConnect).not.toHaveBeenCalled();
  });

  it('supports keyboard activation for compact provider rows', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const actions = createActions();
    const state = createState();

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: { ...state, providers: state.view?.providers ?? [] },
          actions,
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    const row = host.querySelector('[data-testid="runtime-provider-row-openrouter"]');
    expect(row?.getAttribute('role')).toBe('button');
    expect(row?.getAttribute('tabindex')).toBe('0');

    await act(async () => {
      row?.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }));
      await Promise.resolve();
    });

    expect(actions.startConnect).toHaveBeenCalledWith('openrouter');
  });

  it('filters providers from the local provider search', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const actions = createActions();
    const openRouterProvider = createState().view!.providers[0];
    const openAiProvider = {
      ...openRouterProvider,
      providerId: 'openai',
      displayName: 'OpenAI',
      recommended: false,
    };

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({
            view: {
              ...createState().view!,
              providers: [openRouterProvider, openAiProvider],
            },
            providers: [openRouterProvider, openAiProvider],
            providerQuery: 'router',
          }),
          actions,
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('OpenRouter');
    expect(host.textContent).not.toContain('OpenAI');

    expect(host.querySelector('[data-testid="runtime-provider-search"]')).not.toBeNull();
  });

  it('does not open a model list for a render-only filtered fallback provider', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const actions = createActions();
    const openRouterProvider = {
      ...createState().view!.providers[0],
      state: 'connected' as const,
      modelCount: 174,
      actions: [],
    };
    const openAiProvider = {
      ...openRouterProvider,
      providerId: 'openai',
      displayName: 'OpenAI',
      recommended: false,
      defaultModelId: 'openai/gpt-5.4-mini-fast',
    };

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({
            view: {
              ...createState().view!,
              providers: [openRouterProvider, openAiProvider],
            },
            providers: [openRouterProvider, openAiProvider],
            selectedProviderId: 'openrouter',
            modelPickerProviderId: 'openrouter',
            modelPickerMode: 'use',
            providerQuery: 'openai',
            models: [
              {
                providerId: 'openrouter',
                modelId: 'openrouter/openai/gpt-oss-20b:free',
                displayName: 'openai/gpt-oss-20b:free',
                sourceLabel: 'OpenRouter',
                free: true,
                default: false,
                availability: 'untested',
              },
            ],
          }),
          actions,
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('OpenAI');
    expect(host.textContent).not.toContain('OpenRouter');
    expect(
      host.querySelector('[data-testid="runtime-provider-model-loading-skeleton"]')
    ).toBeNull();
  });

  it('opens the OpenCode provider directory and renders directory rows', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const actions = createActions();

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({
            directoryLoaded: true,
            directoryTotalCount: 115,
            directoryEntries: [
              {
                providerId: 'deepseek',
                displayName: 'DeepSeek',
                state: 'available',
                setupKind: 'available-readonly',
                ownership: [],
                recommended: false,
                modelCount: 62,
                defaultModelId: null,
                authMethods: [],
                actions: [
                  {
                    id: 'configure',
                    label: 'Configure manually',
                    enabled: false,
                    disabledReason: 'OpenCode did not advertise API-key auth',
                    requiresSecret: false,
                    ownershipScope: 'runtime',
                  },
                ],
                sources: ['opencode-provider'],
                sourceLabel: 'OpenCode catalog',
                providerSource: 'models.dev',
                detail: 'Models are visible, but no connected credential was reported',
                metadata: {
                  hasKnownModels: true,
                  requiresManualConfig: false,
                  supportedInlineAuth: false,
                  configuredAuthless: false,
                },
              },
              {
                providerId: 'cloudflare-workers-ai',
                displayName: 'Cloudflare Workers AI',
                state: 'not-connected',
                setupKind: 'connect-api-key',
                ownership: [],
                recommended: false,
                modelCount: 8,
                defaultModelId: null,
                authMethods: ['api'],
                actions: [
                  {
                    id: 'connect',
                    label: 'Connect',
                    enabled: true,
                    disabledReason: null,
                    requiresSecret: true,
                    ownershipScope: 'managed',
                  },
                ],
                sources: ['opencode-provider'],
                sourceLabel: 'OpenCode catalog',
                providerSource: 'models.dev',
                detail: 'App-managed API-key setup is available for this provider',
                metadata: {
                  hasKnownModels: true,
                  requiresManualConfig: false,
                  supportedInlineAuth: true,
                  configuredAuthless: false,
                },
              },
            ],
          }),
          actions,
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('115 OpenCode providers');
    expect(host.textContent).toContain('DeepSeek');
    expect(host.textContent).toContain('Cloudflare Workers AI');
    expect(host.textContent).toContain('62 models');
    expect(host.textContent).toContain('OpenCode catalog');
    expect(host.querySelector('[data-testid="runtime-provider-search"]')).not.toBeNull();

    await act(async () => {
      host
        .querySelector('[data-testid="runtime-provider-directory-row-deepseek"]')
        ?.dispatchEvent(new MouseEvent('click', { bubbles: true }));
      await Promise.resolve();
    });

    expect(actions.selectDirectoryProvider).not.toHaveBeenCalled();
    expect(actions.startConnect).not.toHaveBeenCalled();

    await act(async () => {
      host
        .querySelector('[data-testid="runtime-provider-directory-row-cloudflare-workers-ai"]')
        ?.dispatchEvent(new MouseEvent('click', { bubbles: true }));
      await Promise.resolve();
    });

    expect(actions.startConnect).toHaveBeenCalledWith('cloudflare-workers-ai');
    expect(actions.selectDirectoryProvider).not.toHaveBeenCalled();
  });

  it('shows an explicit zero-provider catalog count', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const actions = createActions();

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({
            directoryLoaded: true,
            directoryTotalCount: 0,
            directoryEntries: [],
          }),
          actions,
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('0 OpenCode providers');
    expect(host.textContent).not.toContain('OpenCode provider catalog.');
  });

  it('uses singular provider catalog copy for one provider', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const actions = createActions();

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({
            directoryLoaded: true,
            directoryTotalCount: 1,
            directoryEntries: [],
          }),
          actions,
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('1 OpenCode provider.');
    expect(host.textContent).not.toContain('1 OpenCode providers');
  });

  it('renders every advertised directory action instead of hiding configure behind connect', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const actions = createActions();

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({
            directoryLoaded: true,
            directoryTotalCount: 1,
            directoryEntries: [
              {
                providerId: 'manual-connectable',
                displayName: 'Manual Connectable',
                state: 'not-connected',
                setupKind: 'connect-api-key',
                ownership: [],
                recommended: false,
                modelCount: 1,
                defaultModelId: null,
                authMethods: ['api'],
                actions: [
                  {
                    id: 'connect',
                    label: 'Connect',
                    enabled: true,
                    disabledReason: null,
                    requiresSecret: true,
                    ownershipScope: 'managed',
                  },
                  {
                    id: 'configure',
                    label: 'Configure manually',
                    enabled: false,
                    disabledReason: 'Manual fallback is also available',
                    requiresSecret: false,
                    ownershipScope: 'runtime',
                  },
                ],
                sources: ['opencode-provider'],
                sourceLabel: 'OpenCode catalog',
                providerSource: 'models.dev',
                detail: null,
                metadata: {
                  hasKnownModels: true,
                  requiresManualConfig: true,
                  supportedInlineAuth: true,
                  configuredAuthless: false,
                },
              },
            ],
          }),
          actions,
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    const row = host.querySelector(
      '[data-testid="runtime-provider-directory-row-manual-connectable"]'
    );
    const actionLabels = Array.from(row?.querySelectorAll('button') ?? []).map((button) =>
      button.textContent?.trim()
    );

    expect(actionLabels).toContain('Connect');
    expect(actionLabels).toContain('Configure manually');
  });

  it('opens model list for configured authless local directory providers', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const actions = createActions();

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({
            directoryLoaded: true,
            directoryTotalCount: 1,
            directoryEntries: [
              {
                providerId: 'llama.cpp',
                displayName: 'llama.cpp',
                state: 'available',
                setupKind: 'available-readonly',
                ownership: [],
                recommended: false,
                modelCount: 1,
                defaultModelId: null,
                authMethods: [],
                actions: [
                  {
                    id: 'test',
                    label: 'Test',
                    enabled: true,
                    disabledReason: null,
                    requiresSecret: false,
                    ownershipScope: 'runtime',
                  },
                ],
                sources: ['config-provider'],
                sourceLabel: 'configured',
                providerSource: null,
                detail: 'Configured local OpenCode model route is available',
                metadata: {
                  hasKnownModels: true,
                  requiresManualConfig: false,
                  supportedInlineAuth: false,
                  configuredAuthless: true,
                },
              },
            ],
          }),
          actions,
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    const row = host.querySelector<HTMLElement>(
      '[data-testid="runtime-provider-directory-row-llama.cpp"]'
    );
    expect(row?.textContent).toContain('Configured local');

    await act(async () => {
      row?.dispatchEvent(new MouseEvent('click', { bubbles: true }));
      await Promise.resolve();
    });

    expect(actions.selectDirectoryProvider).toHaveBeenCalledWith('llama.cpp');
  });

  it('uses the unified provider search when compact search has no matches', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const actions = createActions();
    const state = createState();

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: {
            ...state,
            providers: state.view?.providers ?? [],
            providerQuery: 'deep',
            directoryLoaded: true,
            directoryTotalCount: 1,
            directoryEntries: [
              {
                providerId: 'deepseek',
                displayName: 'DeepSeek',
                state: 'available',
                setupKind: 'available-readonly',
                ownership: [],
                recommended: false,
                modelCount: 62,
                defaultModelId: null,
                authMethods: [],
                actions: [],
                sources: ['opencode-provider'],
                sourceLabel: 'OpenCode catalog',
                providerSource: 'models.dev',
                detail: 'Models are visible, but no connected credential was reported',
                metadata: {
                  hasKnownModels: true,
                  requiresManualConfig: false,
                  supportedInlineAuth: false,
                  configuredAuthless: false,
                },
              },
            ],
          },
          actions,
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('DeepSeek');
    expect(host.textContent).not.toContain('Search all OpenCode providers');
  });

  it('renders connected provider model picker actions', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const actions = createActions();
    const connectedProvider = {
      providerId: 'openrouter',
      displayName: 'OpenRouter',
      state: 'connected' as const,
      ownership: ['managed'] as const,
      recommended: true,
      modelCount: 174,
      defaultModelId: null,
      authMethods: ['api'] as const,
      actions: [
        {
          id: 'use' as const,
          label: 'Use',
          enabled: true,
          disabledReason: null,
          requiresSecret: false,
          ownershipScope: 'runtime' as const,
        },
        {
          id: 'set-default' as const,
          label: 'Set default',
          enabled: true,
          disabledReason: null,
          requiresSecret: false,
          ownershipScope: 'runtime' as const,
        },
      ],
      detail: null,
    };
    const state = createState({
      view: {
        ...createState().view!,
        providers: [connectedProvider],
      },
      providers: [connectedProvider],
      modelPickerProviderId: 'openrouter',
      modelPickerMode: 'use',
      models: [
        {
          providerId: 'openrouter',
          modelId: 'openrouter/openai/gpt-oss-20b:free',
          displayName: 'openai/gpt-oss-20b:free',
          sourceLabel: 'OpenRouter',
          free: true,
          default: false,
          availability: 'untested',
        },
        {
          providerId: 'openrouter',
          modelId: 'opencode/big-pickle',
          displayName: 'opencode/big-pickle',
          sourceLabel: 'OpenCode',
          free: false,
          default: false,
          availability: 'untested',
        },
        {
          providerId: 'openrouter',
          modelId: 'openrouter/qwen/qwen3-coder-plus',
          displayName: 'qwen/qwen3-coder-plus',
          sourceLabel: 'OpenRouter',
          free: false,
          default: false,
          availability: 'untested',
        },
        {
          providerId: 'openrouter',
          modelId: 'openrouter/openai/gpt-oss-120b:free',
          displayName: 'openai/gpt-oss-120b:free',
          sourceLabel: 'OpenRouter',
          free: true,
          default: false,
          availability: 'untested',
        },
        {
          providerId: 'openrouter',
          modelId: 'opencode/minimax-m2.5-free',
          displayName: 'minimax-m2.5-free',
          sourceLabel: 'OpenCode',
          free: true,
          default: false,
          availability: 'untested',
        },
        {
          providerId: 'openrouter',
          modelId: 'openrouter/mistralai/codestral-2508',
          displayName: 'mistralai/codestral-2508',
          sourceLabel: 'OpenRouter',
          free: false,
          default: false,
          availability: 'untested',
        },
        {
          providerId: 'openrouter',
          modelId: 'openrouter/anthropic/claude-sonnet-4.6',
          displayName: 'anthropic/claude-sonnet-4.6',
          sourceLabel: 'OpenRouter',
          free: false,
          default: false,
          availability: 'untested',
        },
      ],
      selectedModelId: 'openrouter/openai/gpt-oss-20b:free',
      modelResults: {
        'openrouter/openai/gpt-oss-20b:free': {
          providerId: 'openrouter',
          modelId: 'openrouter/openai/gpt-oss-20b:free',
          ok: true,
          availability: 'available',
          message: 'Model probe passed',
          diagnostics: [],
        },
      },
    });

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state,
          actions,
          disabled: false,
          projectPath: '/tmp/project',
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('openrouter/openai/gpt-oss-20b:free');
    expect(host.textContent).toContain('Saved for team picker');
    expect(host.textContent).toContain('Model probe passed');
    expect(host.textContent).toContain('Recommended');
    expect(host.textContent).toContain('Not recommended');
    expect(host.textContent).toContain('Not verified in OpenCode');
    expect(host.textContent).toContain('Tested');
    expect(host.textContent).toContain('Tested with limits');
    expect(host.textContent).toContain('Recommended only');
    expect(host.textContent).not.toContain('Set OpenCode default');
    expect(
      Array.from(host.querySelectorAll('button')).some(
        (button) => button.textContent?.trim() === 'Save for team picker'
      )
    ).toBe(false);
    expect(
      host.querySelector('[data-testid="runtime-provider-logo-openrouter"] svg')
    ).not.toBeNull();
    const connectedBadge = Array.from(host.querySelectorAll('span')).find(
      (span) => span.textContent === 'Connected'
    );
    expect(connectedBadge).toBeInstanceOf(HTMLSpanElement);
    expect(connectedBadge?.style.color).toBeTruthy();
    const modelSearch = host.querySelector<HTMLInputElement>(
      '[data-testid="runtime-provider-model-search"]'
    );
    const modelList = host.querySelector<HTMLElement>(
      '[data-testid="runtime-provider-model-list"]'
    );
    expect(modelSearch?.style.paddingLeft).toBe('42px');
    expect(modelList?.style.maxHeight).toBe('300px');
    expect(host.textContent).not.toContain('OpenRouterfree');
    const firstTestButton = Array.from(host.querySelectorAll('button')).find(
      (button) => button.textContent?.trim() === 'Test'
    );
    expect(firstTestButton?.className).toContain('border');
    const modelResult = host.querySelector<HTMLElement>(
      '[data-testid="runtime-provider-model-result-openrouter/openai/gpt-oss-20b:free"]'
    );
    expect(modelResult).toBeInstanceOf(HTMLElement);
    expect(modelResult?.style.color).toBe('#86efac');
    expect((host.textContent ?? '').indexOf('mistralai/codestral-2508')).toBeLessThan(
      (host.textContent ?? '').indexOf('qwen/qwen3-coder-plus')
    );
    expect((host.textContent ?? '').indexOf('opencode/big-pickle')).toBeLessThan(
      (host.textContent ?? '').indexOf('minimax-m2.5-free')
    );
    expect((host.textContent ?? '').indexOf('mistralai/codestral-2508')).toBeLessThan(
      (host.textContent ?? '').indexOf('minimax-m2.5-free')
    );
    expect((host.textContent ?? '').indexOf('minimax-m2.5-free')).toBeLessThan(
      (host.textContent ?? '').indexOf('qwen/qwen3-coder-plus')
    );
    expect((host.textContent ?? '').indexOf('qwen/qwen3-coder-plus')).toBeLessThan(
      (host.textContent ?? '').indexOf('openrouter/openai/gpt-oss-20b:free')
    );
    await act(async () => {
      host
        .querySelector(
          '[data-testid="runtime-provider-model-row-openrouter/openai/gpt-oss-20b:free"]'
        )
        ?.dispatchEvent(new MouseEvent('click', { bubbles: true }));
      await Promise.resolve();
    });

    expect(actions.useModelForNewTeams).toHaveBeenCalledWith('openrouter/openai/gpt-oss-20b:free');
    expect(actions.selectProvider).not.toHaveBeenCalled();

    vi.mocked(actions.useModelForNewTeams).mockClear();
    await act(async () => {
      const notRecommendedRow = host.querySelector(
        '[data-testid="runtime-provider-model-row-openrouter/openai/gpt-oss-20b:free"]'
      );
      const notRecommendedTestButton = Array.from(
        notRecommendedRow?.querySelectorAll('button') ?? []
      ).find((button) => button.textContent?.trim() === 'Test');
      notRecommendedTestButton?.dispatchEvent(
        new KeyboardEvent('keydown', { key: 'Enter', bubbles: true })
      );
      await Promise.resolve();
    });

    expect(actions.useModelForNewTeams).not.toHaveBeenCalled();

    await act(async () => {
      const notRecommendedRow = host.querySelector(
        '[data-testid="runtime-provider-model-row-openrouter/openai/gpt-oss-20b:free"]'
      );
      const notRecommendedTestButton = Array.from(
        notRecommendedRow?.querySelectorAll('button') ?? []
      ).find((button) => button.textContent?.trim() === 'Test');
      notRecommendedTestButton?.dispatchEvent(new MouseEvent('click', { bubbles: true }));
      await Promise.resolve();
    });

    expect(actions.testModel).toHaveBeenCalledWith(
      'openrouter',
      'openrouter/openai/gpt-oss-20b:free'
    );
    expect(actions.useModelForNewTeams).not.toHaveBeenCalled();
  });

  it('filters provider model picker rows to free models', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const actions = createActions();
    const connectedProvider = {
      ...createState().view!.providers[0],
      state: 'connected' as const,
      ownership: ['managed'] as const,
      modelCount: 2,
      actions: [],
    };

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({
            view: {
              ...createState().view!,
              providers: [connectedProvider],
            },
            providers: [connectedProvider],
            selectedProviderId: 'openrouter',
            modelPickerProviderId: 'openrouter',
            modelPickerMode: 'use',
            models: [
              {
                providerId: 'openrouter',
                modelId: 'openrouter/anthropic/claude-haiku-4.5',
                displayName: 'anthropic/claude-haiku-4.5',
                sourceLabel: 'OpenRouter',
                free: true,
                default: false,
                availability: 'untested',
                routeKind: 'connected_provider',
              },
              {
                providerId: 'openrouter',
                modelId: 'openrouter/anthropic/claude-sonnet-4.6',
                displayName: 'anthropic/claude-sonnet-4.6',
                sourceLabel: 'OpenRouter',
                free: false,
                default: false,
                availability: 'untested',
                routeKind: 'connected_provider',
              },
            ],
          }),
          actions,
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('Free only');
    expect(host.textContent).toContain('anthropic/claude-haiku-4.5');
    expect(host.textContent).toContain('anthropic/claude-sonnet-4.6');

    await act(async () => {
      host.querySelector<HTMLElement>('#runtime-provider-openrouter-free-only')?.click();
      await Promise.resolve();
    });

    expect(host.textContent).toContain('anthropic/claude-haiku-4.5');
    expect(host.textContent).not.toContain('anthropic/claude-sonnet-4.6');
  });

  it('keeps the model search input enabled while model results are loading', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const actions = createActions();
    const connectedProvider = {
      ...createState().view!.providers[0],
      state: 'connected' as const,
      ownership: ['managed'] as const,
      modelCount: 174,
      actions: [
        {
          id: 'use' as const,
          label: 'Use',
          enabled: true,
          disabledReason: null,
          requiresSecret: false,
          ownershipScope: 'runtime' as const,
        },
      ],
    };

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({
            view: {
              ...createState().view!,
              providers: [connectedProvider],
            },
            providers: [connectedProvider],
            selectedProviderId: 'openrouter',
            modelPickerProviderId: 'openrouter',
            modelPickerMode: 'use',
            modelQuery: 'claude',
            modelsLoading: true,
          }),
          actions,
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    const searchInput = host.querySelector<HTMLInputElement>(
      '[data-testid="runtime-provider-model-search"]'
    );

    expect(searchInput).not.toBeNull();
    expect(searchInput?.disabled).toBe(false);
    expect(searchInput?.value).toBe('claude');
    expect(host.querySelector('[data-testid="runtime-provider-model-loading-skeleton"]')).not.toBe(
      null
    );
  });

  it('does not expose disabled model rows as active buttons', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const actions = createActions();
    const connectedProvider = {
      ...createState().view!.providers[0],
      state: 'connected' as const,
      ownership: ['managed'] as const,
      modelCount: 1,
      actions: [],
    };

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({
            view: {
              ...createState().view!,
              providers: [connectedProvider],
            },
            providers: [connectedProvider],
            selectedProviderId: 'openrouter',
            modelPickerProviderId: 'openrouter',
            modelPickerMode: 'use',
            models: [
              {
                providerId: 'openrouter',
                modelId: 'openrouter/google/gemini-3-flash-preview',
                displayName: 'google/gemini-3-flash-preview',
                sourceLabel: 'OpenRouter',
                free: false,
                default: false,
                availability: 'untested',
              },
            ],
          }),
          actions,
          disabled: true,
        })
      );
      await Promise.resolve();
    });

    const row = host.querySelector<HTMLElement>(
      '[data-testid="runtime-provider-model-row-openrouter/google/gemini-3-flash-preview"]'
    );

    expect(row?.getAttribute('role')).toBeNull();
    expect(row?.getAttribute('aria-disabled')).toBe('true');
    expect(row?.tabIndex).toBe(-1);

    await act(async () => {
      row?.dispatchEvent(new MouseEvent('click', { bubbles: true }));
      await Promise.resolve();
    });

    expect(actions.useModelForNewTeams).not.toHaveBeenCalled();
  });

  it('keeps directory provider models visible when a model row is selected', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const actions = createActions();
    const provider = {
      providerId: 'openrouter',
      displayName: 'OpenRouter',
      state: 'connected' as const,
      ownership: ['managed'] as const,
      recommended: true,
      modelCount: 174,
      defaultModelId: null,
      authMethods: ['api'] as const,
      actions: [],
      sources: ['opencode-provider'] as const,
      sourceLabel: 'OpenCode catalog',
      providerSource: 'models.dev',
      detail: 'Connected via app-managed OpenCode credential',
      setupKind: 'connected' as const,
      metadata: {
        hasKnownModels: true,
        requiresManualConfig: false,
        supportedInlineAuth: true,
        configuredAuthless: false,
      },
    };
    const state = createState({
      providers: [],
      directoryLoaded: true,
      directoryEntries: [provider],
      directoryTotalCount: 1,
      selectedProviderId: 'openrouter',
      modelPickerProviderId: 'openrouter',
      modelPickerMode: 'use',
      models: [
        {
          providerId: 'openrouter',
          modelId: 'openrouter/google/gemini-3-flash-preview',
          displayName: 'google/gemini-3-flash-preview',
          sourceLabel: 'OpenRouter',
          free: false,
          default: false,
          availability: 'untested',
        },
      ],
    });

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state,
          actions,
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    await act(async () => {
      host
        .querySelector(
          '[data-testid="runtime-provider-model-row-openrouter/google/gemini-3-flash-preview"]'
        )
        ?.dispatchEvent(new MouseEvent('click', { bubbles: true }));
      await Promise.resolve();
    });

    expect(actions.useModelForNewTeams).toHaveBeenCalledWith(
      'openrouter/google/gemini-3-flash-preview'
    );
    expect(actions.selectDirectoryProvider).not.toHaveBeenCalled();
    expect(host.textContent).toContain('google/gemini-3-flash-preview');
    expect(host.textContent).not.toContain('No models found.');
  });

  it('renders verified brand icons for common OpenCode providers', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const actions = createActions();
    const baseProvider = createState().view!.providers[0];
    const providers = [
      { providerId: 'openrouter', displayName: 'OpenRouter' },
      { providerId: 'opencode', displayName: 'OpenCode Zen' },
      { providerId: 'openai', displayName: 'OpenAI' },
      { providerId: 'anthropic', displayName: 'Anthropic' },
      { providerId: 'google', displayName: 'Google' },
      { providerId: 'google-vertex', displayName: 'Vertex' },
      { providerId: 'vercel', displayName: 'Vercel AI Gateway' },
      { providerId: 'mistral', displayName: 'Mistral' },
      { providerId: 'github-models', displayName: 'GitHub Models' },
      { providerId: 'perplexity-agent', displayName: 'Perplexity Agent' },
      { providerId: 'nvidia', displayName: 'Nvidia' },
      { providerId: 'minimax', displayName: 'MiniMax' },
      { providerId: 'cloudflare-ai-gateway', displayName: 'Cloudflare AI Gateway' },
      { providerId: 'cloudflare-workers-ai', displayName: 'Cloudflare Workers AI' },
      { providerId: 'gitlab-duo', displayName: 'GitLab Duo' },
      { providerId: 'poe', displayName: 'Poe' },
    ].map((provider) => ({
      ...baseProvider,
      ...provider,
      state: 'not-connected' as const,
      recommended: false,
    }));

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({
            view: {
              ...createState().view!,
              providers,
            },
            providers,
          }),
          actions,
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    for (const provider of providers) {
      const logo = host.querySelector(
        `[data-testid="runtime-provider-logo-${provider.providerId}"]`
      );
      expect(logo).not.toBeNull();
      expect(logo?.className).toContain('runtime-provider-brand-icon');
      expect(logo?.querySelector('svg,img')).not.toBeNull();
      expect(logo?.getAttribute('style')).toContain('--runtime-provider-brand-fallback-background');
      expect(logo?.getAttribute('style')).toContain('--runtime-provider-brand-fallback-border');
      if (logo?.querySelector('svg')) {
        expect(logo.getAttribute('style')).toContain('--runtime-provider-brand-fallback-color');
      }
    }
  });

  it('uses Models.dev logos only for verified providers and initials for unknown providers', async () => {
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const actions = createActions();
    const baseProvider = createState().view!.providers[0];
    const providers = [
      { providerId: 'xai', displayName: 'xAI', logo: 'xai' },
      { providerId: 'groq', displayName: 'Groq', logo: 'groq' },
      { providerId: 'deepseek', displayName: 'DeepSeek', logo: 'deepseek' },
      { providerId: 'cohere', displayName: 'Cohere', logo: 'cohere' },
      {
        providerId: 'cloudferro-sherlock',
        displayName: 'CloudFerro Sherlock',
        logo: 'cloudferro-sherlock',
      },
      { providerId: 'clarifai', displayName: 'Clarifai', label: 'CL' },
      { providerId: 'unknown-provider', displayName: 'Unknown Provider', label: 'UN' },
    ].map((provider) => ({
      ...baseProvider,
      ...provider,
      state: 'not-connected' as const,
      recommended: false,
    }));

    await act(async () => {
      root.render(
        React.createElement(RuntimeProviderManagementPanelView, {
          state: createState({
            view: {
              ...createState().view!,
              providers,
            },
            providers,
          }),
          actions,
          disabled: false,
        })
      );
      await Promise.resolve();
    });

    for (const provider of providers) {
      const logo = host.querySelector(
        `[data-testid="runtime-provider-logo-${provider.providerId}"]`
      );
      if ('logo' in provider) {
        const image = logo?.querySelector('img') as HTMLImageElement | null;
        expect(image?.src).toContain(`https://models.dev/logos/${provider.logo}.svg`);
        expect(logo?.className).toContain('runtime-provider-brand-icon');
      } else {
        expect(logo?.textContent).toBe(provider.label);
      }
    }
  });
});
