// src/config/queryClient.test.ts
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { QueryClientProvider } from '@tanstack/react-query';
import { renderHook, waitFor } from '@testing-library/react';
import { useMutation } from '@tanstack/react-query';
import type { ReactNode } from 'react';
import { queryClient } from './queryClient';
import * as loggerModule from '../services/logger.client';

vi.mock('../services/logger.client', () => ({
  logger: {
    error: vi.fn(),
    info: vi.fn(),
    warn: vi.fn(),
    debug: vi.fn(),
  },
}));

const mockedLogger = vi.mocked(loggerModule.logger);

describe('queryClient', () => {
  beforeEach(() => {
    vi.resetAllMocks();
    queryClient.clear();
  });

  afterEach(() => {
    queryClient.clear();
  });

  describe('configuration', () => {
    it('should have correct default query options', () => {
      const defaultOptions = queryClient.getDefaultOptions();

      expect(defaultOptions.queries?.staleTime).toBe(1000 * 60 * 5); // 5 minutes
      expect(defaultOptions.queries?.gcTime).toBe(1000 * 60 * 30); // 30 minutes
      expect(defaultOptions.queries?.retry).toBe(1);
      expect(defaultOptions.queries?.refetchOnWindowFocus).toBe(false);
      expect(defaultOptions.queries?.refetchOnMount).toBe(true);
      expect(defaultOptions.queries?.refetchOnReconnect).toBe(false);
    });

    it('should have correct default mutation options', () => {
      const defaultOptions = queryClient.getDefaultOptions();

      expect(defaultOptions.mutations?.retry).toBe(0);
      expect(defaultOptions.mutations?.onError).toBeDefined();
    });
  });

  describe('mutation onError callback', () => {
    const wrapper = ({ children }: { children: ReactNode }) => (
      <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
    );

    it('should log Error instance message on mutation error', async () => {
      const testError = new Error('Test mutation error');

      const { result } = renderHook(
        () =>
          useMutation({
            mutationFn: async () => {
              throw testError;
            },
          }),
        { wrapper },
      );

      result.current.mutate();

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

      expect(mockedLogger.error).toHaveBeenCalledWith('Mutation error', {
        error: 'Test mutation error',
      });
    });

    it('should log "Unknown error" for non-Error objects', async () => {
      const { result } = renderHook(
        () =>
          useMutation({
            mutationFn: async () => {
              throw 'string error';
            },
          }),
        { wrapper },
      );

      result.current.mutate();

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

      expect(mockedLogger.error).toHaveBeenCalledWith('Mutation error', {
        error: 'Unknown error',
      });
    });
  });
});
