import { renderHook, waitFor } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import React from 'react';
import { http, HttpResponse } from 'msw';
import { setupServer } from 'msw/node';
import { useProviders, useCreateProvider, useUpdateProvider, useDeleteProvider } from '@/hooks/useProviders';
import type { Provider, CreateProviderInput, UpdateProviderInput } from '@/types';
import { MessagePlugin } from 'tdesign-react';

// Mock MessagePlugin
vi.mock('tdesign-react', () => ({
  MessagePlugin: {
    success: vi.fn(),
    error: vi.fn(),
  },
}));

// Test data
const mockProviders: Provider[] = [
  {
    id: 'provider-1',
    name: 'OpenAI',
    apiKey: 'sk-xxx',
    baseUrl: 'https://api.openai.com',
    enabled: true,
    createdAt: '2026-01-01T00:00:00Z',
    updatedAt: '2026-01-01T00:00:00Z',
  },
  {
    id: 'provider-2',
    name: 'Anthropic',
    apiKey: 'sk-yyy',
    baseUrl: 'https://api.anthropic.com',
    enabled: false,
    createdAt: '2026-02-01T00:00:00Z',
    updatedAt: '2026-02-01T00:00:00Z',
  },
];

const mockCreatedProvider: Provider = {
  id: 'provider-3',
  name: 'NewProvider',
  apiKey: 'sk-zzz',
  baseUrl: 'https://api.newprovider.com',
  enabled: true,
  createdAt: '2026-03-01T00:00:00Z',
  updatedAt: '2026-03-01T00:00:00Z',
};

// MSW handlers
const handlers = [
  http.get('/api/providers', () => {
    return HttpResponse.json(mockProviders);
  }),
  http.post('/api/providers', async ({ request }) => {
    const body = await request.json() as Record<string, unknown>;
    return HttpResponse.json({
      ...mockCreatedProvider,
      ...body,
    });
  }),
  http.put('/api/providers/:id', async ({ request, params }) => {
    const body = await request.json() as Record<string, unknown>;
    const existing = mockProviders.find((p) => p.id === params['id']);
    return HttpResponse.json({ ...existing, ...body });
  }),
  http.delete('/api/providers/:id', () => {
    return new HttpResponse(null, { status: 204 });
  }),
];

const server = setupServer(...handlers);

function createTestQueryClient() {
  return new QueryClient({
    defaultOptions: {
      queries: { retry: false },
      mutations: { retry: false },
    },
  });
}

function createWrapper() {
  const testQueryClient = createTestQueryClient();
  return function Wrapper({ children }: { children: React.ReactNode }) {
    return (
      <QueryClientProvider client={testQueryClient}>
        {children}
      </QueryClientProvider>
    );
  };
}

beforeAll(() => server.listen());
afterEach(() => {
  server.resetHandlers();
  vi.clearAllMocks();
});
afterAll(() => server.close());

describe('useProviders', () => {
  it('fetches and returns provider list', async () => {
    const { result } = renderHook(() => useProviders(), {
      wrapper: createWrapper(),
    });

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

    expect(result.current.data).toEqual(mockProviders);
    expect(result.current.data).toHaveLength(2);
    expect(result.current.data![0]!.name).toBe('OpenAI');
    expect(result.current.data![1]!.name).toBe('Anthropic');
  });
});

describe('useCreateProvider', () => {
  it('calls API and invalidates provider queries', async () => {
    const queryClient = createTestQueryClient();
    const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries');

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

    const { result } = renderHook(() => useCreateProvider(), {
      wrapper: Wrapper,
    });

    const input: CreateProviderInput = {
      id: 'provider-3',
      name: 'NewProvider',
      apiKey: 'sk-zzz',
      baseUrl: 'https://api.newprovider.com',
      enabled: true,
    };

    result.current.mutate(input);

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

    expect(result.current.data).toMatchObject({
      id: 'provider-3',
      name: 'NewProvider',
    });
    expect(invalidateSpy).toHaveBeenCalledWith({ queryKey: ['providers'] });
    expect(MessagePlugin.success).toHaveBeenCalledWith('供应商创建成功');
  });

  it('calls message.error on failure', async () => {
    server.use(
      http.post('/api/providers', () => {
        return HttpResponse.json({ message: '创建失败' }, { status: 500 });
      }),
    );

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

    const input: CreateProviderInput = {
      id: 'provider-3',
      name: 'NewProvider',
      apiKey: 'sk-zzz',
      baseUrl: 'https://api.newprovider.com',
      enabled: true,
    };

    result.current.mutate(input);

    await waitFor(() => expect(result.current.isError).toBe(true));
    expect(MessagePlugin.error).toHaveBeenCalled();
  });
});

describe('useUpdateProvider', () => {
  it('calls API and invalidates provider queries', async () => {
    const queryClient = createTestQueryClient();
    const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries');

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

    const { result } = renderHook(() => useUpdateProvider(), {
      wrapper: Wrapper,
    });

    const input: UpdateProviderInput = { name: 'UpdatedProvider' };

    result.current.mutate({ id: 'provider-1', input });

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

    expect(result.current.data).toMatchObject({
      name: 'UpdatedProvider',
    });
    expect(invalidateSpy).toHaveBeenCalledWith({ queryKey: ['providers'] });
    expect(MessagePlugin.success).toHaveBeenCalledWith('供应商更新成功');
  });

  it('calls message.error on failure', async () => {
    server.use(
      http.put('/api/providers/:id', () => {
        return HttpResponse.json({ message: '更新失败' }, { status: 500 });
      }),
    );

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

    result.current.mutate({ id: 'provider-1', input: { name: 'Updated' } });

    await waitFor(() => expect(result.current.isError).toBe(true));
    expect(MessagePlugin.error).toHaveBeenCalled();
  });
});

describe('useDeleteProvider', () => {
  it('calls API and invalidates provider queries', async () => {
    const queryClient = createTestQueryClient();
    const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries');

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

    const { result } = renderHook(() => useDeleteProvider(), {
      wrapper: Wrapper,
    });

    result.current.mutate('provider-1');

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

    expect(invalidateSpy).toHaveBeenCalledWith({ queryKey: ['providers'] });
    expect(MessagePlugin.success).toHaveBeenCalledWith('供应商删除成功');
  });

  it('calls message.error on failure', async () => {
    server.use(
      http.delete('/api/providers/:id', () => {
        return HttpResponse.json({ message: '删除失败' }, { status: 500 });
      }),
    );

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

    result.current.mutate('provider-1');

    await waitFor(() => expect(result.current.isError).toBe(true));
    expect(MessagePlugin.error).toHaveBeenCalled();
  });
});
