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,
    directoryEntries: [],
    directoryTotalCount: null,
    directoryNextCursor: null,
    directoryLoaded: false,
    directorySelectedProviderId: null,
    directorySupported: true,
    activeFormProviderId: null,
    setupForm: null,
    setupFormLoading: false,
    setupFormError: null,
    setupSubmitError: null,
    setupMetadata: {},
    apiKeyValue: '',
    modelPickerProviderId: null,
    modelPickerMode: null,
    modelQuery: '',
    models: [],
    modelsLoading: false,
    modelsError: null,
    selectedModelId: null,
    testingModelIds: [],
    savingDefaultModelId: null,
    modelResults: {},
    loading: false,
    savingProviderId: null,
    error: 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()),
  };
}

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-loading-skeleton"]')).not.toBeNull();
    expect(host.querySelectorAll('.skeleton-shimmer').length).toBeGreaterThanOrEqual(10);
    expect(host.textContent).toContain('Checking...');
    const refreshButton = Array.from(host.querySelectorAll('button')).find((button) =>
      button.textContent?.includes('Checking...')
    );
    expect(refreshButton?.disabled).toBe(true);
  });

  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,
                },
              },
              {
                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,
                },
              },
            ],
          }),
          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,
                },
              },
            ],
          }),
          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('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,
                },
              },
            ],
          },
          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,
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('openrouter/openai/gpt-oss-20b:free');
    expect(host.textContent).toContain('Used for new teams');
    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() === 'Use for new teams'
      )
    ).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('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,
      },
    };
    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);
      }
    }
  });
});
