import { act, renderHook } from '@testing-library/react';
import type { ReactNode } from 'react';
import { describe, expect, it, vi } from 'vitest';

import type { PicloudClient, RealtimeEvent, Unsubscribe } from '../src/index.js';
import { PicloudProvider, useTopic } from '../src/react/index.js';

type Cb = (e: RealtimeEvent<unknown>) => void;

function fakeClient() {
  const unsubscribe = vi.fn();
  let captured: Cb | null = null;
  const subscribe = vi.fn(
    (_topic: string, cb: Cb): Unsubscribe => {
      captured = cb;
      return unsubscribe as unknown as Unsubscribe;
    }
  );
  const client = { subscribe } as unknown as PicloudClient;
  return { client, subscribe, unsubscribe, emit: (e: RealtimeEvent<unknown>) => captured?.(e) };
}

describe('react useTopic', () => {
  it('subscribes on mount, accumulates messages, unsubscribes on unmount', () => {
    const { client, subscribe, unsubscribe, emit } = fakeClient();
    const wrapper = ({ children }: { children: ReactNode }) =>
      PicloudProvider({ client, children });

    const { result, unmount } = renderHook(() => useTopic<{ n: number }>('chat'), { wrapper });

    expect(subscribe).toHaveBeenCalledTimes(1);
    expect(result.current).toEqual([]);

    act(() => emit({ topic: 'chat', message: { n: 1 }, published_at: 't' }));
    act(() => emit({ topic: 'chat', message: { n: 2 }, published_at: 't' }));
    expect(result.current).toEqual([{ n: 1 }, { n: 2 }]);

    unmount();
    expect(unsubscribe).toHaveBeenCalledTimes(1);
  });
});
