import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { getApiClient, postApiClient } from '@/utils/apiClient';
import Cookies from 'js-cookie';
import { mockApiSuccess, mockApiError, setupFetchMock } from '@tests/mocks/api';

describe('apiClient', () => {
  let fetchMock: ReturnType<typeof vi.fn>;

  beforeEach(() => {
    fetchMock = setupFetchMock();
    vi.mocked(Cookies.get).mockReturnValue('mock-token-123');
  });

  afterEach(() => {
    vi.clearAllMocks();
  });

  describe('getApiClient', () => {
    it('should make GET request with correct headers', async () => {
      const mockData = { id: '1', name: 'Test' };
      fetchMock.mockResolvedValue(mockApiSuccess(mockData));

      const result = await getApiClient('products');

      expect(fetchMock).toHaveBeenCalledWith(
        expect.stringContaining('products'),
        expect.objectContaining({
          method: 'GET',
          headers: expect.objectContaining({
            Authorization: 'Bearer mock-token-123',
          }),
        })
      );
      expect(result).toEqual(mockData);
    });

    it('should handle query parameters', async () => {
      const mockData = [{ id: '1' }];
      fetchMock.mockResolvedValue(mockApiSuccess(mockData));

      await getApiClient('products', { category: 'test', limit: '10' });

      const callUrl = fetchMock.mock.calls[0][0];
      expect(callUrl).toContain('category=test');
      expect(callUrl).toContain('limit=10');
    });

    it('should handle API errors', async () => {
      fetchMock.mockResolvedValue(mockApiError('Not found', 404));

      await expect(getApiClient('products/999')).rejects.toThrow('Not found');
    });

    it('should work without token', async () => {
      vi.mocked(Cookies.get).mockReturnValue(undefined);
      const mockData = { public: 'data' };
      fetchMock.mockResolvedValue(mockApiSuccess(mockData));

      const result = await getApiClient('public/data');

      expect(result).toEqual(mockData);
    });
  });

  describe('postApiClient', () => {
    it('should make POST request with JSON payload', async () => {
      const mockData = { success: true };
      const payload = { name: 'Test Product', price: 1999 };
      
      fetchMock.mockResolvedValue(mockApiSuccess(mockData));

      const result = await postApiClient('products', payload);

      expect(fetchMock).toHaveBeenCalledWith(
        expect.stringContaining('products'),
        expect.objectContaining({
          method: 'POST',
          headers: expect.objectContaining({
            'Content-Type': 'application/json',
            Authorization: 'Bearer mock-token-123',
          }),
          body: JSON.stringify(payload),
        })
      );
    });

    it('should handle POST errors', async () => {
      const payload = { name: 'Test' };
      fetchMock.mockResolvedValue(mockApiError('Validation failed', 400));

      await expect(postApiClient('products', payload)).rejects.toThrow();
    });
  });
});
