import { describe, it, expect, vi } from 'vitest';
import { renderHook, waitFor, act } from '@testing-library/react';
import type { ReactNode } from 'react';
import { MessagingProvider } from '../provider';
import { MockAdapter } from '../adapters/mock';
import { useConversations } from './use-conversations';
import type { MessagingAdapter } from '../adapter';

const wrap = (adapter: MessagingAdapter) =>
  function Wrapper({ children }: { children: ReactNode }) {
    return <MessagingProvider adapter={adapter}>{children}</MessagingProvider>;
  };

describe('useConversations', () => {
  it('starts loading, then resolves the adapter list', async () => {
    const { result } = renderHook(() => useConversations(), { wrapper: wrap(new MockAdapter()) });
    expect(result.current.loading).toBe(true);

    await waitFor(() => expect(result.current.loading).toBe(false));
    // 2 DMs/groups + 2 channels I'm a member of (the un-joined public channel is browse-only).
    expect(result.current.conversations).toHaveLength(4);
    expect(result.current.conversations[0]!.threadId).toBe('th_mock_1');
    expect(result.current.error).toBeNull();
  });

  it('surfaces adapter failure as error state and never throws', async () => {
    const adapter = new MockAdapter();
    vi.spyOn(adapter, 'listConversations').mockRejectedValue(new Error('data door down'));

    const { result } = renderHook(() => useConversations(), { wrapper: wrap(adapter) });
    await waitFor(() => expect(result.current.loading).toBe(false));
    expect(result.current.error).toBe('data door down');
    expect(result.current.conversations).toEqual([]);
  });

  it('refetch picks up newly opened threads', async () => {
    const adapter = new MockAdapter();
    const { result } = renderHook(() => useConversations(), { wrapper: wrap(adapter) });
    await waitFor(() => expect(result.current.conversations).toHaveLength(4));

    await act(async () => {
      await adapter.openThread({ participantIds: ['pp_dan'] });
    });
    await act(async () => {
      result.current.refetch();
    });

    await waitFor(() => expect(result.current.conversations).toHaveLength(5));
  });
});
