import { describe, it, expect, vi, beforeEach } from 'vitest';
import { renderHook, waitFor, act } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import React from 'react';

// Mock apiClient
vi.mock('../../api/client', () => ({
  default: {
    get: vi.fn(),
    post: vi.fn(),
    patch: vi.fn(),
    delete: vi.fn(),
  },
}));

import {
  useServices,
  useService,
  useCreateService,
  useUpdateService,
  useDeleteService,
  useReorderServices,
} from '../useServices';
import apiClient from '../../api/client';

// Create wrapper
const createWrapper = () => {
  const queryClient = new QueryClient({
    defaultOptions: {
      queries: { retry: false },
      mutations: { retry: false },
    },
  });

  return function Wrapper({ children }: { children: React.ReactNode }) {
    return React.createElement(QueryClientProvider, { client: queryClient }, children);
  };
};

describe('useServices hooks', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe('useServices', () => {
    it('fetches services and transforms data', async () => {
      const mockServices = [
        { id: 1, name: 'Haircut', duration: 30, price: '25.00', description: 'Basic haircut' },
        { id: 2, name: 'Color', duration_minutes: 60, price: '75.00', variable_pricing: true },
      ];
      vi.mocked(apiClient.get).mockResolvedValue({ data: mockServices });

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

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

      expect(apiClient.get).toHaveBeenCalledWith('/services/');
      expect(result.current.data).toHaveLength(2);
      expect(result.current.data?.[0]).toEqual(expect.objectContaining({
        id: '1',
        name: 'Haircut',
        durationMinutes: 30,
        price: 25,
        description: 'Basic haircut',
      }));
      expect(result.current.data?.[1].variable_pricing).toBe(true);
    });

    it('handles missing fields with defaults', async () => {
      const mockServices = [
        { id: 1, name: 'Service', price: '10.00', duration: 15 },
      ];
      vi.mocked(apiClient.get).mockResolvedValue({ data: mockServices });

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

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

      expect(result.current.data?.[0].description).toBe('');
      expect(result.current.data?.[0].displayOrder).toBe(0);
      expect(result.current.data?.[0].photos).toEqual([]);
    });
  });

  describe('useService', () => {
    it('fetches single service by id', async () => {
      const mockService = {
        id: 1,
        name: 'Premium Cut',
        duration: 45,
        price: '50.00',
        description: 'Premium service',
        photos: ['photo1.jpg'],
      };
      vi.mocked(apiClient.get).mockResolvedValue({ data: mockService });

      const { result } = renderHook(() => useService('1'), {
        wrapper: createWrapper(),
      });

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

      expect(apiClient.get).toHaveBeenCalledWith('/services/1/');
      expect(result.current.data?.name).toBe('Premium Cut');
    });

    it('does not fetch when id is empty', async () => {
      const { result } = renderHook(() => useService(''), {
        wrapper: createWrapper(),
      });

      await waitFor(() => {
        expect(result.current.isLoading).toBe(false);
      });

      expect(apiClient.get).not.toHaveBeenCalled();
    });
  });

  describe('useCreateService', () => {
    it('creates service with correct field mapping', async () => {
      vi.mocked(apiClient.post).mockResolvedValue({ data: { id: 1 } });

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

      await act(async () => {
        await result.current.mutateAsync({
          name: 'New Service',
          durationMinutes: 45,
          price: 35.99,
          description: 'Test description',
          photos: ['photo.jpg'],
        });
      });

      expect(apiClient.post).toHaveBeenCalledWith('/services/', {
        name: 'New Service',
        duration: 45,
        price: '35.99',
        description: 'Test description',
        photos: ['photo.jpg'],
      });
    });

    it('includes pricing fields when provided', async () => {
      vi.mocked(apiClient.post).mockResolvedValue({ data: { id: 1 } });

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

      await act(async () => {
        await result.current.mutateAsync({
          name: 'Priced Service',
          durationMinutes: 30,
          price: 100,
          variable_pricing: true,
          deposit_amount: 25,
          deposit_percent: 25,
        });
      });

      expect(apiClient.post).toHaveBeenCalledWith('/services/', expect.objectContaining({
        variable_pricing: true,
        deposit_amount: 25,
        deposit_percent: 25,
      }));
    });
  });

  describe('useUpdateService', () => {
    it('updates service with mapped fields', async () => {
      vi.mocked(apiClient.patch).mockResolvedValue({ data: {} });

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

      await act(async () => {
        await result.current.mutateAsync({
          id: '1',
          updates: { name: 'Updated Name', price: 50 },
        });
      });

      expect(apiClient.patch).toHaveBeenCalledWith('/services/1/', {
        name: 'Updated Name',
        price: '50',
      });
    });
  });

  describe('useDeleteService', () => {
    it('deletes service by id', async () => {
      vi.mocked(apiClient.delete).mockResolvedValue({});

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

      await act(async () => {
        await result.current.mutateAsync('3');
      });

      expect(apiClient.delete).toHaveBeenCalledWith('/services/3/');
    });
  });

  describe('useReorderServices', () => {
    it('sends reorder request with converted ids', async () => {
      vi.mocked(apiClient.post).mockResolvedValue({ data: {} });

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

      await act(async () => {
        await result.current.mutateAsync(['3', '1', '2']);
      });

      expect(apiClient.post).toHaveBeenCalledWith('/services/reorder/', {
        order: [3, 1, 2],
      });
    });
  });
});
