import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { renderHook, waitFor } from '@testing-library/react-native';
import React, { type PropsWithChildren } from 'react';

import {
  useConversations,
  useCreateConversation,
  useDeleteConversation,
} from '@/features/conversation/hooks';
import { conversationKeys } from '@/features/conversation/query-keys';

// ─── Mocks ───

const mockList = jest.fn();
const mockCreate = jest.fn();
const mockDelete = jest.fn();

jest.mock('@/features/conversation/api', () => ({
  conversationApi: {
    list: () => mockList(),
    create: () => mockCreate(),
    delete: (id: string) => mockDelete(id),
    detail: jest.fn(),
    end: jest.fn(),
    messages: jest.fn(),
    organize: jest.fn(),
  },
}));

// ─── Helpers ───

let queryClient: QueryClient;

function createWrapper() {
  queryClient = new QueryClient({
    defaultOptions: {
      queries: { retry: false, gcTime: Infinity },
      mutations: { retry: false },
    },
  });

  return function Wrapper({ children }: PropsWithChildren) {
    return (
      <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
    );
  };
}

afterEach(async () => {
  await queryClient?.cancelQueries();
  queryClient?.clear();
  jest.clearAllMocks();
});

const fakeConversations = [
  {
    id: 'c1',
    title: '第一次对话',
    avatarUrl: null,
    latestMessagePreview: '你好',
    latestMessageTime: 1000,
    startedAt: 1000,
    unreadCount: 0,
    isDefaultAssistant: false,
    hasUserMessage: true,
  },
];

// ─── Tests ───

describe('useConversations', () => {
  test('fetches conversation list', async () => {
    mockList.mockResolvedValue(fakeConversations);

    const { result } = renderHook(() => useConversations(), {
      wrapper: createWrapper(),
    });

    await waitFor(() => {
      expect(result.current.isSuccess).toBe(true);
    });

    expect(result.current.data).toEqual(fakeConversations);
  });
});

describe('useCreateConversation', () => {
  test('adds new conversation to list cache on success', async () => {
    const newConversation = {
      id: 'c2',
      user_id: 'u1',
      started_at: '2026-01-01T00:00:00Z',
      status: 'active',
    };
    mockCreate.mockResolvedValue(newConversation);

    const wrapper = createWrapper();
    queryClient.setQueryData(conversationKeys.lists(), fakeConversations);

    const { result } = renderHook(() => useCreateConversation(), { wrapper });

    await result.current.mutateAsync();

    await waitFor(() => {
      expect(result.current.isSuccess).toBe(true);
    });

    const list = queryClient.getQueryData(conversationKeys.lists()) as Array<{
      id: string;
    }>;
    expect(list[0].id).toBe('c2');
    expect(list).toHaveLength(2);
  });
});

describe('useDeleteConversation', () => {
  test('removes conversation from list cache on success', async () => {
    mockDelete.mockResolvedValue({ message: 'ok' });

    const wrapper = createWrapper();
    queryClient.setQueryData(conversationKeys.lists(), fakeConversations);

    const { result } = renderHook(() => useDeleteConversation(), { wrapper });

    await result.current.mutateAsync('c1');

    await waitFor(() => {
      expect(result.current.isSuccess).toBe(true);
    });

    const list = queryClient.getQueryData(conversationKeys.lists()) as Array<{
      id: string;
    }>;
    expect(list).toHaveLength(0);
  });
});
