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 {
  useCustomers,
  useCreateCustomer,
  useUpdateCustomer,
  useDeleteCustomer,
} from '../useCustomers';
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('useCustomers hooks', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe('useCustomers', () => {
    it('fetches customers and transforms data', async () => {
      const mockCustomers = [
        {
          id: 1,
          name: 'John Doe',
          email: 'john@example.com',
          phone: '555-1234',
          total_spend: '150.00',
          status: 'Active',
          user_id: 10,
        },
        {
          id: 2,
          user: { name: 'Jane Smith', email: 'jane@example.com' },
          phone: '',
          total_spend: '0',
          status: 'Inactive',
          user: 20,
        },
      ];
      vi.mocked(apiClient.get).mockResolvedValue({ data: mockCustomers });

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

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

      expect(apiClient.get).toHaveBeenCalledWith('/customers/?');
      expect(result.current.data).toHaveLength(2);
      expect(result.current.data?.[0]).toEqual(expect.objectContaining({
        id: '1',
        name: 'John Doe',
        email: 'john@example.com',
        totalSpend: 150,
        status: 'Active',
      }));
    });

    it('applies status filter', async () => {
      vi.mocked(apiClient.get).mockResolvedValue({ data: [] });

      renderHook(() => useCustomers({ status: 'Active' }), {
        wrapper: createWrapper(),
      });

      await waitFor(() => {
        expect(apiClient.get).toHaveBeenCalledWith('/customers/?status=Active');
      });
    });

    it('applies search filter', async () => {
      vi.mocked(apiClient.get).mockResolvedValue({ data: [] });

      renderHook(() => useCustomers({ search: 'john' }), {
        wrapper: createWrapper(),
      });

      await waitFor(() => {
        expect(apiClient.get).toHaveBeenCalledWith('/customers/?search=john');
      });
    });

    it('applies multiple filters', async () => {
      vi.mocked(apiClient.get).mockResolvedValue({ data: [] });

      renderHook(() => useCustomers({ status: 'Blocked', search: 'test' }), {
        wrapper: createWrapper(),
      });

      await waitFor(() => {
        expect(apiClient.get).toHaveBeenCalledWith('/customers/?status=Blocked&search=test');
      });
    });

    it('handles customers with last_visit date', async () => {
      const mockCustomers = [
        {
          id: 1,
          name: 'Customer',
          email: 'c@example.com',
          total_spend: '0',
          last_visit: '2024-01-15T10:00:00Z',
          user_id: 1,
        },
      ];
      vi.mocked(apiClient.get).mockResolvedValue({ data: mockCustomers });

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

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

      expect(result.current.data?.[0].lastVisit).toBeInstanceOf(Date);
    });
  });

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

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

      await act(async () => {
        await result.current.mutateAsync({
          userId: '5',
          phone: '555-9999',
          city: 'Denver',
          state: 'CO',
          zip: '80202',
          status: 'Active',
        });
      });

      expect(apiClient.post).toHaveBeenCalledWith('/customers/', {
        user: 5,
        phone: '555-9999',
        city: 'Denver',
        state: 'CO',
        zip: '80202',
        status: 'Active',
        avatar_url: undefined,
        tags: undefined,
      });
    });
  });

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

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

      await act(async () => {
        await result.current.mutateAsync({
          id: '1',
          updates: {
            phone: '555-0000',
            status: 'Blocked',
            tags: ['vip'],
          },
        });
      });

      expect(apiClient.patch).toHaveBeenCalledWith('/customers/1/', {
        phone: '555-0000',
        city: undefined,
        state: undefined,
        zip: undefined,
        status: 'Blocked',
        avatar_url: undefined,
        tags: ['vip'],
      });
    });
  });

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

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

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

      expect(apiClient.delete).toHaveBeenCalledWith('/customers/7/');
    });
  });
});
