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

interface PortStub {
  name: string;
  postMessage: ReturnType<typeof vi.fn>;
  onMessage: { addListener: ReturnType<typeof vi.fn> };
  onDisconnect: { addListener: ReturnType<typeof vi.fn> };
  disconnect: ReturnType<typeof vi.fn>;
}

interface ChromeStub {
  runtime: {
    id: string;
    sendMessage: (m: unknown) => void;
    onMessage: { addListener: ReturnType<typeof vi.fn> };
    connect: () => PortStub;
  };
}

interface GlobalWithChrome {
  chrome?: ChromeStub;
  MediaRecorder?: { isTypeSupported: (mime: string) => boolean };
}

function buildChromeStub(calls: unknown[]): ChromeStub {
  return {
    runtime: {
      id: 'ext-id-test',
      sendMessage: (m: unknown) => {
        calls.push(m);
      },
      onMessage: { addListener: vi.fn() },
      connect: () => ({
        name: 'video-keepalive',
        postMessage: vi.fn(),
        onMessage: { addListener: vi.fn() },
        onDisconnect: { addListener: vi.fn() },
        disconnect: vi.fn(),
      }),
    },
  };
}

describe('OFFSCREEN_READY handshake', () => {
  beforeEach(() => {
    vi.resetModules();
    (globalThis as unknown as GlobalWithChrome).MediaRecorder = {
      isTypeSupported: vi.fn().mockReturnValue(true),
    };
  });

  it('sends OFFSCREEN_READY after listener registration', async () => {
    const calls: unknown[] = [];
    const stub = buildChromeStub(calls);
    (globalThis as unknown as GlobalWithChrome).chrome = stub;
    await import('../../src/offscreen/recorder');
    expect(stub.runtime.onMessage.addListener).toHaveBeenCalled();
    expect(calls).toEqual(
      expect.arrayContaining([expect.objectContaining({ type: 'OFFSCREEN_READY' })])
    );
    const readyCount = calls.filter(
      (m): m is { type: string } =>
        typeof m === 'object' && m !== null && (m as { type?: unknown }).type === 'OFFSCREEN_READY'
    ).length;
    expect(readyCount).toBe(1);
  });
});
