import { afterEach, describe, expect, test } from 'bun:test';
import { act, cleanup, render } from '@testing-library/react';
import { useAudioRecording } from './useAudioRecording';

/**
 * The microphone is the one resource in this app the browser tells the user about: a recording indicator
 * stays lit in the tab strip until every track is stopped. Nothing here released it on unmount, so closing
 * a Chat panel mid-recording left the light on for the life of the tab with no way to switch it off.
 *
 * The stubs are the smallest thing that can answer "was the track stopped": a stream that counts stops and
 * a recorder that reports its state. Neither the real MediaRecorder nor a real device is involved.
 */

const stopped: string[] = [];

const fakeStream = (label: string) => ({
  getTracks: () => [{ stop: () => stopped.push(label) }],
});

class FakeMediaRecorder {
  state: 'recording' | 'inactive' = 'inactive';
  stream = fakeStream('track');
  mimeType = 'audio/webm';
  ondataavailable: ((ev: { data: Blob }) => void) | null = null;
  onstop: (() => void) | null = null;
  start() {
    this.state = 'recording';
  }
  stop() {
    this.state = 'inactive';
    this.onstop?.();
  }
}

const install = () => {
  stopped.length = 0;
  Object.assign(globalThis, { MediaRecorder: FakeMediaRecorder });
  Object.defineProperty(globalThis.navigator, 'mediaDevices', {
    configurable: true,
    value: { getUserMedia: async () => fakeStream('track') },
  });
};

type Handle = { toggle: () => Promise<void>; recording: boolean };

const handle: Handle = { toggle: async () => {}, recording: false };

const Probe = () => {
  const runner = useAudioRecording(() => {});
  handle.toggle = runner.toggleRecording;
  handle.recording = runner.recording;
  return null;
};

afterEach(cleanup);

describe('useAudioRecording', () => {
  test('releases the microphone when its component goes away mid-recording', async () => {
    install();
    const view = render(<Probe />);

    await act(async () => {
      await handle.toggle();
    });
    expect(handle.recording).toBe(true);
    expect(stopped).toEqual([]);

    view.unmount();

    // Not "the user pressed stop" — the panel was closed, swapped or remounted while still recording, and
    // that is the case that used to leak.
    expect(stopped).toEqual(['track']);
  });

  test('unmounting when nothing was ever recorded does nothing', () => {
    install();
    const view = render(<Probe />);

    view.unmount();

    expect(stopped).toEqual([]);
  });
});
