// src/hooks/queries/useFlyersQuery.test.tsx
import { renderHook, waitFor } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import type { ReactNode } from 'react';
import { useFlyersQuery } from './useFlyersQuery';
import * as apiClient from '../../services/apiClient';

vi.mock('../../services/apiClient');

const mockedApiClient = vi.mocked(apiClient);

describe('useFlyersQuery', () => {
  let queryClient: QueryClient;

  const wrapper = ({ children }: { children: ReactNode }) => (
    <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
  );

  beforeEach(() => {
    vi.resetAllMocks();
    queryClient = new QueryClient({
      defaultOptions: {
        queries: { retry: false },
      },
    });
  });

  it('should fetch flyers successfully with default params', async () => {
    const mockFlyers = [
      { flyer_id: 1, store_name: 'Store A', valid_from: '2024-01-01', valid_to: '2024-01-07' },
      { flyer_id: 2, store_name: 'Store B', valid_from: '2024-01-01', valid_to: '2024-01-07' },
    ];
    mockedApiClient.fetchFlyers.mockResolvedValue({
      ok: true,
      json: () => Promise.resolve(mockFlyers),
    } as Response);

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

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

    expect(mockedApiClient.fetchFlyers).toHaveBeenCalledWith(20, 0);
    expect(result.current.data).toEqual(mockFlyers);
  });

  it('should fetch flyers with custom limit and offset', async () => {
    const mockFlyers = [{ flyer_id: 3, store_name: 'Store C' }];
    mockedApiClient.fetchFlyers.mockResolvedValue({
      ok: true,
      json: () => Promise.resolve(mockFlyers),
    } as Response);

    const { result } = renderHook(() => useFlyersQuery(10, 5), { wrapper });

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

    expect(mockedApiClient.fetchFlyers).toHaveBeenCalledWith(10, 5);
    expect(result.current.data).toEqual(mockFlyers);
  });

  it('should handle API error with error message', async () => {
    mockedApiClient.fetchFlyers.mockResolvedValue({
      ok: false,
      status: 500,
      json: () => Promise.resolve({ message: 'Server error' }),
    } as Response);

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

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

    expect(result.current.error?.message).toBe('Server error');
  });

  it('should handle API error without message', async () => {
    mockedApiClient.fetchFlyers.mockResolvedValue({
      ok: false,
      status: 500,
      json: () => Promise.reject(new Error('Parse error')),
    } as Response);

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

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

    expect(result.current.error?.message).toBe('Request failed with status 500');
  });

  it('should use fallback message when error.message is empty', async () => {
    mockedApiClient.fetchFlyers.mockResolvedValue({
      ok: false,
      status: 500,
      json: () => Promise.resolve({ message: '' }),
    } as Response);

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

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

    expect(result.current.error?.message).toBe('Failed to fetch flyers');
  });

  it('should return empty array for no flyers', async () => {
    mockedApiClient.fetchFlyers.mockResolvedValue({
      ok: true,
      json: () => Promise.resolve([]),
    } as Response);

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

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

    expect(result.current.data).toEqual([]);
  });
});
