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

type DashboardModule = {
  DashboardPage: {
    render: (el: unknown, client: unknown) => Promise<void>;
    teardown: () => void;
  };
};

function deepClone(value: unknown) {
  return JSON.parse(JSON.stringify(value));
}

function setByPath(target: Record<string, any>, path: string, value: unknown) {
  const parts = path.split('.');
  let cursor: Record<string, any> = target;
  for (let i = 0; i < parts.length - 1; i++) {
    const key = parts[i];
    const next = cursor[key];
    if (!next || typeof next !== 'object' || Array.isArray(next)) {
      cursor[key] = {};
    }
    cursor = cursor[key] as Record<string, any>;
  }
  cursor[parts[parts.length - 1]] = value;
}

function createInitialConfig() {
  return {
    automation: {
      delivery_mode: 'shared_session',
      daily_briefing: {
        enabled: true,
        name: 'daily-briefing',
        schedule: '0 8 * * *',
        timezone: 'UTC',
        model_tier: 'default',
        output: {
          channel: 'telegram',
          peer: '12345',
        },
        prompt: 'Summarize the top priorities.',
      },
    },
    memory: {
      daily_log: { enabled: true },
      proactive_extract: { enabled: true, min_tool_calls: 2 },
    },
    tts: {
      enabled: false,
      enabled_channels: [],
    },
    agents: {
      primary_tier: 'default',
      delegation: {
        compaction: 'fast',
        memory_extraction: 'fast',
        classification: 'fast',
        tool_summarisation: 'fast',
        complex_reasoning: 'complex',
      },
      background_models: {
        compaction: { enabled: true, provider: 'openai', model: 'gpt-4o-mini', fallback_tier: 'fast' },
        memory_extraction: { enabled: true, provider: 'openai', model: 'gpt-4o-mini', fallback_tier: 'fast' },
        classification: { enabled: true, provider: 'openai', model: 'gpt-4o-mini', fallback_tier: 'fast' },
        tool_summarisation: { enabled: true, provider: 'openai', model: 'gpt-4o-mini', fallback_tier: 'fast' },
        complex_reasoning: { enabled: true, provider: 'openai', model: 'gpt-4o-mini', fallback_tier: 'default' },
      },
    },
    models: {
      default: { provider: 'openai', model: 'gpt-4o-mini' },
      fast: { provider: 'openai', model: 'gpt-4o-mini' },
      complex: { provider: 'anthropic', model: 'claude-3-7-sonnet' },
      local: { provider: 'ollama', model: 'llama3.2' },
    },
    councils: {
      enabled: true,
      defaults: { max_rounds: 2 },
      groups: {
        D: { model_tier: 'complex', arbiter_agent: 'council_d_arbiter', freethinker_agent: 'council_d_freethinker' },
        P: { model_tier: 'complex', arbiter_agent: 'council_p_arbiter', freethinker_agent: 'council_p_freethinker' },
      },
      meta_model_tier: 'complex',
      meta_arbiter_agent: 'council_meta_arbiter',
      scaffold_path: 'docs/councils/ai-council-production-scaffold.json',
    },
  };
}

function createMockClient() {
  const state = {
    config: createInitialConfig(),
    localBackends: [
      {
        id: 'ollama',
        provider: 'ollama',
        name: 'Ollama',
        unit: 'ollama.service',
        configured: true,
        loadState: 'loaded',
        activeState: 'active',
        subState: 'running',
        unitFileState: 'enabled',
        description: 'Ollama daemon',
        pid: 111,
        result: 'success',
        statusText: 'active (running)',
        availableActions: ['restart', 'stop', 'update'],
      },
      {
        id: 'llamacpp',
        provider: 'llamacpp',
        name: 'llama.cpp server',
        unit: 'llama-server.service',
        configured: true,
        loadState: 'loaded',
        activeState: 'inactive',
        subState: 'dead',
        unitFileState: 'enabled',
        description: 'llama.cpp daemon',
        pid: null,
        result: 'success',
        statusText: 'inactive/dead',
        availableActions: ['start', 'restart', 'update'],
      },
    ],
    dockerDependencies: [
      {
        id: 'whisper',
        name: 'Whisper (whisper.cpp)',
        service: 'whisper-server',
        configured: true,
        state: 'running',
        health: 'healthy',
        statusText: 'Up 2 minutes (healthy)',
        containerName: 'flynn-whisper-server-1',
        availableActions: ['restart', 'stop', 'update'],
      },
      {
        id: 'brave-search',
        name: 'Brave Search',
        service: 'brave-search',
        configured: true,
        state: 'running',
        health: 'healthy',
        statusText: 'Up 2 minutes',
        containerName: 'brave-search',
        availableActions: ['restart', 'stop', 'update'],
      },
    ],
    observabilitySources: [
      {
        id: 'systemd:flynn',
        name: 'Flynn daemon',
        kind: 'systemd_system',
        runtime: 'systemd_system',
        status: 'running',
        graphCapable: true,
        logCapable: true,
      },
      {
        id: 'docker:whisper',
        name: 'Whisper (whisper.cpp)',
        kind: 'docker_dependency',
        runtime: 'docker_compose',
        status: 'running',
        graphCapable: true,
        logCapable: true,
      },
    ],
    observabilitySeries: {
      generatedAt: 1700000000000,
      windowMinutes: 60,
      bucketSeconds: 30,
      series: [
        {
          sourceId: 'systemd:flynn',
          points: [
            { ts: 1700000000000, stateCode: 3, healthCode: 2, errorCount: 0, restartCount: 0 },
            { ts: 1700000030000, stateCode: 3, healthCode: 2, errorCount: 0, restartCount: 1 },
          ],
        },
        {
          sourceId: 'docker:whisper',
          points: [
            { ts: 1700000000000, stateCode: 3, healthCode: 2, errorCount: 0, restartCount: 0 },
            { ts: 1700000030000, stateCode: 2, healthCode: 1, errorCount: 1, restartCount: 0 },
          ],
        },
      ],
    },
    serviceLogs: {
      'systemd:flynn': {
        sourceId: 'systemd:flynn',
        fetchedAt: 1700000005000,
        redacted: true,
        truncated: false,
        lines: [
          { ts: 1700000004000, level: 'info', text: 'gateway online' },
          { ts: 1700000004500, level: 'warn', text: 'queue depth rising' },
        ],
      },
      'docker:whisper': {
        sourceId: 'docker:whisper',
        fetchedAt: 1700000006000,
        redacted: false,
        truncated: false,
        lines: [
          { ts: 1700000005500, level: 'error', text: 'model load failed' },
        ],
      },
    } as Record<string, unknown>,
    calls: [] as Array<{ method: string; params?: Record<string, unknown> }>,
  };

  const client = {
    async call(method: string, params?: Record<string, unknown>) {
      state.calls.push({ method, params });
      if (method === 'system.metrics') {
        return {
          messagesProcessed: 0,
          queueDepth: 0,
          uptime: 30,
          activeRequests: 0,
          errors: 0,
          modelCalls: {
            total: 0,
            avgLatency: 0,
            errorRate: 0,
            recentCalls: [],
          },
        };
      }
      if (method === 'system.events') {
        return { events: [] };
      }
      if (method === 'system.activeRequests') {
        return { requests: [] };
      }
      if (method === 'system.health') {
        return { sessions: 0 };
      }
      if (method === 'system.services') {
        return { services: [] };
      }
      if (method === 'system.localBackends') {
        return { backends: deepClone(state.localBackends) };
      }
      if (method === 'system.dockerDependencies') {
        return { dependencies: deepClone(state.dockerDependencies) };
      }
      if (method === 'system.sessionAnalytics') {
        return {
          daily: [],
          topSessions: [],
          topTools: [],
          topTopics: [],
          totalSessions: 0,
          totalMessages: 0,
          averageMessagesPerSession: 0,
        };
      }
      if (method === 'system.observabilitySources') {
        return { sources: deepClone(state.observabilitySources) };
      }
      if (method === 'system.observabilitySeries') {
        return deepClone(state.observabilitySeries);
      }
      if (method === 'system.serviceLogs') {
        const sourceId = String(params?.sourceId ?? '');
        return deepClone(state.serviceLogs[sourceId] ?? {
          sourceId,
          fetchedAt: Date.now(),
          redacted: false,
          truncated: false,
          lines: [],
        });
      }
      if (method === 'system.contextUsage') {
        return { sessions: [] };
      }
      if (method === 'system.modelCatalog') {
        return {
          providers: [
            { provider: 'openai', models: ['gpt-4o-mini', 'gpt-4.1-mini'] },
            { provider: 'anthropic', models: ['claude-3-7-sonnet'] },
            { provider: 'ollama', models: ['llama3.2'] },
          ],
        };
      }
      if (method === 'config.get') {
        return deepClone(state.config);
      }
      if (method === 'config.patch') {
        const patches = (params?.patches ?? {}) as Record<string, unknown>;
        for (const [key, value] of Object.entries(patches)) {
          setByPath(state.config as Record<string, any>, key, value);
        }
        return {
          applied: Object.keys(patches),
          rejected: [],
          persisted: true,
        };
      }
      if (method === 'tools.invoke') {
        if (params?.tool === 'council.run') {
          return {
            success: true,
            output: JSON.stringify({
              pipeline_version: '1.0',
              stop_snapshot: { stop_reason: 'complete', round_reached: 1 },
              conversations: [],
            }),
          };
        }
        if (params?.tool === 'cron.trigger') {
          return { success: true, output: 'Triggered.' };
        }
        return { success: true, output: '' };
      }
      if (method === 'system.localBackendControl') {
        const backendId = String(params?.backend ?? '');
        const action = String(params?.action ?? '');
        const backend = state.localBackends.find((entry) => entry.id === backendId);
        if (!backend) {
          throw new Error(`Unknown backend: ${backendId}`);
        }

        if (action === 'start' || action === 'restart') {
          backend.activeState = 'active';
          backend.subState = 'running';
          backend.statusText = 'active (running)';
          backend.pid = backend.id === 'ollama' ? 222 : 333;
          backend.availableActions = ['restart', 'stop', 'update'];
          backend.result = 'success';
        } else if (action === 'stop') {
          backend.activeState = 'inactive';
          backend.subState = 'dead';
          backend.statusText = 'inactive/dead';
          backend.pid = null;
          backend.availableActions = ['start', 'restart', 'update'];
          backend.result = 'success';
        } else if (action === 'update') {
          backend.result = 'success';
        }

        return {
          backend: backendId,
          action,
          status: deepClone(backend),
          message: action === 'update' ? 'Updated backend assets' : undefined,
        };
      }
      if (method === 'system.dockerDependencyControl') {
        const dependencyId = String(params?.dependency ?? '');
        const action = String(params?.action ?? '');
        const dependency = state.dockerDependencies.find((entry) => entry.id === dependencyId);
        if (!dependency) {
          throw new Error(`Unknown dependency: ${dependencyId}`);
        }

        if (action === 'start' || action === 'restart') {
          dependency.state = 'running';
          dependency.health = 'healthy';
          dependency.statusText = 'running (healthy)';
          dependency.containerName = String(dependency.service ?? dependency.id ?? '');
          dependency.availableActions = ['restart', 'stop', 'update'];
        } else if (action === 'stop') {
          dependency.state = 'stopped';
          dependency.health = 'none';
          dependency.statusText = 'stopped';
          dependency.availableActions = ['start', 'restart', 'update'];
        } else if (action === 'update') {
          dependency.state = 'running';
          dependency.health = 'healthy';
          dependency.statusText = 'running (healthy)';
          dependency.availableActions = ['restart', 'stop', 'update'];
        }

        return {
          dependency: dependencyId,
          action,
          status: deepClone(dependency),
          message: action === 'update' ? 'Pulled latest image' : undefined,
        };
      }
      return null;
    },
  };

  return { state, client };
}

async function flush() {
  await Promise.resolve();
  await Promise.resolve();
  await Promise.resolve();
}

function getControlCurrentValue(control: any) {
  if (control.tagName === 'SELECT') {
    const options = Array.from(control.options ?? []) as any[];
    const selectedOption = options.find((option) => option.selected);
    if (selectedOption?.value) {
      return String(selectedOption.value);
    }
    if (typeof control.selectedIndex === 'number' && control.selectedIndex >= 0 && options[control.selectedIndex]?.value) {
      return String(options[control.selectedIndex].value);
    }
    if (typeof control.getAttribute === 'function') {
      return String(control.getAttribute('value') ?? '');
    }
    return String(selectedOption?.value ?? '');
  }
  return String(control.value ?? '');
}

function setControlToDraft(control: any, windowObj: any) {
  if (control.tagName === 'SELECT') {
    const options = Array.from(control.options ?? []) as any[];
    if (options.length > 1) {
      const currentIdx = Math.max(0, options.findIndex((option: any) => option.value === control.value));
      const nextIdx = (currentIdx + 1) % options.length;
      options.forEach((option) => {
        option.selected = false;
      });
      options[nextIdx].selected = true;
    }
  } else if (control.tagName === 'INPUT' && control.type === 'checkbox') {
    control.checked = !control.checked;
  } else if (control.tagName === 'INPUT' && control.type === 'number') {
    control.value = control.value === '6' ? '5' : '6';
  } else {
    control.value = `draft-${control.id}`;
  }

  control.dispatchEvent(new windowObj.Event('input', { bubbles: true }));
  control.dispatchEvent(new windowObj.Event('change', { bubbles: true }));
}

describe('DashboardPage assistant controls', () => {
  let container: any;
  let windowObj: any;
  let DashboardPage: DashboardModule['DashboardPage'];

  beforeEach(async () => {
    const { document, window } = parseHTML('<!doctype html><html><body><div id="root"></div></body></html>') as unknown as {
      document: any;
      window: any;
    };
    windowObj = window;
    (globalThis as any).document = document;
    (globalThis as any).window = window;
    container = document.getElementById('root');

    // @ts-expect-error dashboard page is a plain JS module without a .d.ts declaration.
    const mod = await import('./dashboard.js') as unknown as DashboardModule;
    DashboardPage = mod.DashboardPage;
  });

  afterEach(() => {
    DashboardPage.teardown();
    vi.useRealTimers();
    delete (globalThis as any).document;
    delete (globalThis as any).window;
  });

  it('preserves unsaved assistant form control values across slow refresh re-renders', async () => {
    vi.useFakeTimers();
    const { state, client } = createMockClient();

    await DashboardPage.render(container, client);

    const controls = Array.from(container.querySelectorAll('#ops-assistant-health input[id], #ops-assistant-health select[id], #ops-assistant-health textarea[id]')) as any[];
    expect(controls.length).toBeGreaterThan(0);

    const expected = new Map<string, { kind: 'value' | 'checkbox'; value: string | boolean }>();
    for (const control of controls) {
      setControlToDraft(control, windowObj);
      if (control.tagName === 'INPUT' && control.type === 'checkbox') {
        expected.set(control.id, { kind: 'checkbox', value: Boolean(control.checked) });
      } else {
        expected.set(control.id, { kind: 'value', value: getControlCurrentValue(control) });
      }
    }

    // Simulate server-side config drift that would overwrite form values without draft preservation.
    state.config.councils.groups.D.model_tier = 'fast';
    state.config.councils.groups.P.model_tier = 'default';
    state.config.models.default.provider = 'anthropic';
    state.config.automation.daily_briefing.output.channel = 'discord';

    await vi.advanceTimersByTimeAsync(10000);
    await flush();

    const after = Array.from(container.querySelectorAll('#ops-assistant-health input[id], #ops-assistant-health select[id], #ops-assistant-health textarea[id]')) as any[];
    const byId = new Map<string, any>(after.map((control) => [String(control.id), control]));

    for (const [id, draft] of expected.entries()) {
      const control = byId.get(id);
      expect(control, `missing control ${id} after re-render`).toBeTruthy();
      if (draft.kind === 'checkbox') {
        expect(Boolean(control.checked)).toBe(draft.value);
      } else {
        expect(getControlCurrentValue(control)).toBe(draft.value);
      }
    }
  });

  it('wires all assistant action buttons to patch/tool calls', async () => {
    const { state, client } = createMockClient();

    await DashboardPage.render(container, client);

    const actionButtons = Array.from(container.querySelectorAll('#ops-assistant-health .assistant-action-btn')) as any[];
    const actions = new Set(actionButtons.map((button) => String(button.getAttribute('data-action'))));
    expect(actions).toEqual(new Set([
      'toggle-announce',
      'toggle-daily-briefing',
      'toggle-memory-daily',
      'toggle-memory-proactive',
      'toggle-tts',
      'playbook-executive',
      'playbook-operator',
      'playbook-focus',
      'playbook-undo',
      'save-model-defaults',
      'save-councils',
      'run-council',
      'save-briefing-output',
      'test-daily-briefing',
    ]));

    const clickAction = async (action: string) => {
      const button = container.querySelector(`#ops-assistant-health .assistant-action-btn[data-action="${action}"]`);
      expect(button, `button missing for ${action}`).toBeTruthy();
      button.dispatchEvent(new windowObj.Event('click', { bubbles: true }));
      await flush();
    };

    const councilTask = container.querySelector('#assist-council-task');
    councilTask.value = 'Design a rollout plan';

    // Ensure briefing output is present for save/test flows.
    const briefChannel = container.querySelector('#assist-brief-channel');
    const briefPeer = container.querySelector('#assist-brief-peer');
    briefChannel.value = 'telegram';
    briefPeer.value = '12345';

    await clickAction('toggle-announce');
    await clickAction('toggle-daily-briefing');
    await clickAction('toggle-memory-daily');
    await clickAction('toggle-memory-proactive');
    await clickAction('toggle-tts');
    await clickAction('playbook-executive');
    await clickAction('playbook-operator');
    await clickAction('playbook-focus');
    await clickAction('playbook-undo');
    await clickAction('save-model-defaults');
    await clickAction('save-councils');

    const councilTask2 = container.querySelector('#assist-council-task');
    councilTask2.value = 'Design a rollout plan';
    await clickAction('run-council');

    const briefChannel2 = container.querySelector('#assist-brief-channel');
    const briefPeer2 = container.querySelector('#assist-brief-peer');
    briefChannel2.value = 'telegram';
    briefPeer2.value = '12345';
    await clickAction('save-briefing-output');

    // Keep daily briefing enabled so button remains active.
    state.config.automation.daily_briefing.enabled = true;
    await clickAction('test-daily-briefing');

    const patchCalls = state.calls.filter((entry) => entry.method === 'config.patch');
    const toolCalls = state.calls.filter((entry) => entry.method === 'tools.invoke');

    expect(patchCalls.length).toBeGreaterThanOrEqual(11);
    expect(patchCalls.some((entry) => Object.prototype.hasOwnProperty.call(entry.params?.patches ?? {}, 'councils.enabled'))).toBe(true);
    expect(patchCalls.some((entry) => Object.prototype.hasOwnProperty.call(entry.params?.patches ?? {}, 'agents.primary_tier'))).toBe(true);
    expect(patchCalls.some((entry) => Object.prototype.hasOwnProperty.call(entry.params?.patches ?? {}, 'automation.daily_briefing.output.channel'))).toBe(true);

    expect(toolCalls.some((entry) => entry.params?.tool === 'council.run')).toBe(true);
    expect(toolCalls.some((entry) => entry.params?.tool === 'cron.trigger')).toBe(true);
  });

  it('renders local backend controls and triggers system.localBackendControl actions', async () => {
    const { state, client } = createMockClient();

    await DashboardPage.render(container, client);

    const restartBtn = container.querySelector('#ops-local-backends .local-backend-action-btn[data-backend-id="ollama"][data-action="restart"]');
    expect(restartBtn).toBeTruthy();
    restartBtn.dispatchEvent(new windowObj.Event('click', { bubbles: true }));
    await flush();

    const startBtn = container.querySelector('#ops-local-backends .local-backend-action-btn[data-backend-id="llamacpp"][data-action="start"]');
    expect(startBtn).toBeTruthy();
    startBtn.dispatchEvent(new windowObj.Event('click', { bubbles: true }));
    await flush();

    const updateBtn = container.querySelector('#ops-local-backends .local-backend-action-btn[data-backend-id="ollama"][data-action="update"]');
    expect(updateBtn).toBeTruthy();
    updateBtn.dispatchEvent(new windowObj.Event('click', { bubbles: true }));
    await flush();

    const backendCalls = state.calls.filter((entry) => entry.method === 'system.localBackendControl');
    expect(backendCalls).toHaveLength(3);
    expect(backendCalls[0].params).toEqual({ backend: 'ollama', action: 'restart' });
    expect(backendCalls[1].params).toEqual({ backend: 'llamacpp', action: 'start' });
    expect(backendCalls[2].params).toEqual({ backend: 'ollama', action: 'update' });
    expect(state.localBackends.find((entry) => entry.id === 'llamacpp')?.activeState).toBe('active');
  });

  it('renders docker dependency status cards', async () => {
    const { client } = createMockClient();

    await DashboardPage.render(container, client);

    const card = container.querySelector('#ops-docker-dependencies');
    expect(card).toBeTruthy();
    expect(String(card.textContent ?? '')).toContain('Whisper (whisper.cpp)');
    expect(String(card.textContent ?? '')).toContain('Brave Search');
    expect(String(card.textContent ?? '')).toContain('whisper-server');
    expect(String(card.textContent ?? '')).toContain('brave-search');
    expect(String(card.textContent ?? '')).toContain('Up 2 minutes (healthy)');
  });

  it('renders docker dependency controls and triggers system.dockerDependencyControl actions', async () => {
    const { state, client } = createMockClient();

    await DashboardPage.render(container, client);

    const restartBtn = container.querySelector('#ops-docker-dependencies .docker-dependency-action-btn[data-dependency-id="whisper"][data-action="restart"]');
    expect(restartBtn).toBeTruthy();
    restartBtn.dispatchEvent(new windowObj.Event('click', { bubbles: true }));
    await flush();

    const stopBtn = container.querySelector('#ops-docker-dependencies .docker-dependency-action-btn[data-dependency-id="whisper"][data-action="stop"]');
    expect(stopBtn).toBeTruthy();
    stopBtn.dispatchEvent(new windowObj.Event('click', { bubbles: true }));
    await flush();

    const startBtn = container.querySelector('#ops-docker-dependencies .docker-dependency-action-btn[data-dependency-id="whisper"][data-action="start"]');
    expect(startBtn).toBeTruthy();
    startBtn.dispatchEvent(new windowObj.Event('click', { bubbles: true }));
    await flush();

    const updateBtn = container.querySelector('#ops-docker-dependencies .docker-dependency-action-btn[data-dependency-id="whisper"][data-action="update"]');
    expect(updateBtn).toBeTruthy();
    updateBtn.dispatchEvent(new windowObj.Event('click', { bubbles: true }));
    await flush();

    const braveRestartBtn = container.querySelector('#ops-docker-dependencies .docker-dependency-action-btn[data-dependency-id="brave-search"][data-action="restart"]');
    expect(braveRestartBtn).toBeTruthy();
    braveRestartBtn.dispatchEvent(new windowObj.Event('click', { bubbles: true }));
    await flush();

    const dependencyCalls = state.calls.filter((entry) => entry.method === 'system.dockerDependencyControl');
    expect(dependencyCalls).toHaveLength(5);
    expect(dependencyCalls[0].params).toEqual({ dependency: 'whisper', action: 'restart' });
    expect(dependencyCalls[1].params).toEqual({ dependency: 'whisper', action: 'stop' });
    expect(dependencyCalls[2].params).toEqual({ dependency: 'whisper', action: 'start' });
    expect(dependencyCalls[3].params).toEqual({ dependency: 'whisper', action: 'update' });
    expect(dependencyCalls[4].params).toEqual({ dependency: 'brave-search', action: 'restart' });
    expect(state.dockerDependencies.find((entry) => entry.id === 'whisper')?.state).toBe('running');
    expect(state.dockerDependencies.find((entry) => entry.id === 'brave-search')?.state).toBe('running');
  });

  it('renders observability graph cards with sampled trend data', async () => {
    const { client } = createMockClient();

    await DashboardPage.render(container, client);

    const card = container.querySelector('#ops-observability-graphs');
    expect(card).toBeTruthy();
    expect(String(card.textContent ?? '')).toContain('Flynn daemon');
    expect(String(card.textContent ?? '')).toContain('Whisper (whisper.cpp)');
    expect(String(card.textContent ?? '')).toContain('Window deltas');
  });

  it('renders service logs and refreshes selected source', async () => {
    const { state, client } = createMockClient();

    await DashboardPage.render(container, client);

    const logsPanel = container.querySelector('#ops-service-logs');
    expect(logsPanel).toBeTruthy();
    expect(String(logsPanel.textContent ?? '')).toContain('gateway online');

    const sourceSelect = container.querySelector('#ops-log-source');
    expect(sourceSelect).toBeTruthy();
    const sourceOptions = Array.from(sourceSelect.options ?? []) as Array<{ value: string; selected: boolean }>;
    sourceOptions.forEach((option) => {
      option.selected = option.value === 'docker:whisper';
    });
    sourceSelect.dispatchEvent(new windowObj.Event('change', { bubbles: true }));
    await flush();

    expect(String(logsPanel.textContent ?? '')).toContain('model load failed');

    const refreshButton = container.querySelector('#ops-log-refresh');
    expect(refreshButton).toBeTruthy();
    refreshButton.dispatchEvent(new windowObj.Event('click', { bubbles: true }));
    await flush();

    const logCalls = state.calls.filter((entry) => entry.method === 'system.serviceLogs');
    expect(logCalls.length).toBeGreaterThanOrEqual(2);
    expect(logCalls.some((entry) => entry.params?.sourceId === 'docker:whisper')).toBe(true);
  });
});
