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 dependencies
vi.mock('../../api/client', () => ({
  default: {
    get: vi.fn(),
    post: vi.fn(),
    patch: vi.fn(),
  },
}));

vi.mock('../../utils/cookies', () => ({
  getCookie: vi.fn(),
}));

import { useCurrentBusiness, useUpdateBusiness, useBusinessUsers, useResources, useCreateResource } from '../useBusiness';
import apiClient from '../../api/client';
import { getCookie } from '../../utils/cookies';

// 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('useBusiness hooks', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe('useCurrentBusiness', () => {
    it('returns null when no token exists', async () => {
      vi.mocked(getCookie).mockReturnValue(null);

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

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

      expect(result.current.data).toBeNull();
      expect(apiClient.get).not.toHaveBeenCalled();
    });

    it('fetches business and transforms data', async () => {
      vi.mocked(getCookie).mockReturnValue('valid-token');

      const mockBusiness = {
        id: 1,
        name: 'Test Business',
        subdomain: 'test',
        primary_color: '#FF0000',
        secondary_color: '#00FF00',
        logo_url: 'https://example.com/logo.png',
        timezone: 'America/Denver',
        timezone_display_mode: 'business',
        tier: 'professional',
        status: 'active',
        created_at: '2024-01-01T00:00:00Z',
        payments_enabled: true,
        plan_permissions: {
          sms_reminders: true,
          api_access: true,
        },
      };
      vi.mocked(apiClient.get).mockResolvedValue({ data: mockBusiness });

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

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

      expect(apiClient.get).toHaveBeenCalledWith('/business/current/');
      expect(result.current.data).toEqual(expect.objectContaining({
        id: '1',
        name: 'Test Business',
        subdomain: 'test',
        primaryColor: '#FF0000',
        secondaryColor: '#00FF00',
        logoUrl: 'https://example.com/logo.png',
        timezone: 'America/Denver',
        plan: 'professional',
        paymentsEnabled: true,
      }));
    });

    it('uses default values for missing fields', async () => {
      vi.mocked(getCookie).mockReturnValue('valid-token');

      const mockBusiness = {
        id: 1,
        name: 'Minimal Business',
        subdomain: 'min',
      };
      vi.mocked(apiClient.get).mockResolvedValue({ data: mockBusiness });

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

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

      expect(result.current.data?.primaryColor).toBe('#3B82F6');
      expect(result.current.data?.secondaryColor).toBe('#1E40AF');
      expect(result.current.data?.logoDisplayMode).toBe('text-only');
      expect(result.current.data?.timezone).toBe('America/New_York');
      expect(result.current.data?.paymentsEnabled).toBe(false);
    });
  });

  describe('useUpdateBusiness', () => {
    it('maps frontend fields to backend fields', async () => {
      vi.mocked(apiClient.patch).mockResolvedValue({ data: {} });

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

      await act(async () => {
        await result.current.mutateAsync({
          name: 'Updated Name',
          primaryColor: '#123456',
          secondaryColor: '#654321',
          timezone: 'America/Los_Angeles',
        });
      });

      expect(apiClient.patch).toHaveBeenCalledWith('/business/current/update/', {
        name: 'Updated Name',
        primary_color: '#123456',
        secondary_color: '#654321',
        timezone: 'America/Los_Angeles',
      });
    });

    it('handles logo fields', async () => {
      vi.mocked(apiClient.patch).mockResolvedValue({ data: {} });

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

      await act(async () => {
        await result.current.mutateAsync({
          logoUrl: 'https://new-logo.com/logo.png',
          emailLogoUrl: 'https://new-logo.com/email.png',
          logoDisplayMode: 'logo-only',
        });
      });

      expect(apiClient.patch).toHaveBeenCalledWith('/business/current/update/', {
        logo_url: 'https://new-logo.com/logo.png',
        email_logo_url: 'https://new-logo.com/email.png',
        logo_display_mode: 'logo-only',
      });
    });

    it('handles booking-related settings', async () => {
      vi.mocked(apiClient.patch).mockResolvedValue({ data: {} });

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

      await act(async () => {
        await result.current.mutateAsync({
          resourcesCanReschedule: true,
          requirePaymentMethodToBook: true,
          cancellationWindowHours: 24,
          lateCancellationFeePercent: 50,
        });
      });

      expect(apiClient.patch).toHaveBeenCalledWith('/business/current/update/', {
        resources_can_reschedule: true,
        require_payment_method_to_book: true,
        cancellation_window_hours: 24,
        late_cancellation_fee_percent: 50,
      });
    });

    it('handles website and dashboard content', async () => {
      vi.mocked(apiClient.patch).mockResolvedValue({ data: {} });

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

      const websitePages = { home: { title: 'Welcome' } };
      const dashboardContent = [{ type: 'text', content: 'Hello' }];

      await act(async () => {
        await result.current.mutateAsync({
          websitePages,
          customerDashboardContent: dashboardContent,
          initialSetupComplete: true,
        });
      });

      expect(apiClient.patch).toHaveBeenCalledWith('/business/current/update/', {
        website_pages: websitePages,
        customer_dashboard_content: dashboardContent,
        initial_setup_complete: true,
      });
    });
  });

  describe('useBusinessUsers', () => {
    it('fetches staff users', async () => {
      const mockUsers = [
        { id: 1, name: 'Staff 1' },
        { id: 2, name: 'Staff 2' },
      ];
      vi.mocked(apiClient.get).mockResolvedValue({ data: mockUsers });

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

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

      expect(apiClient.get).toHaveBeenCalledWith('/staff/');
      expect(result.current.data).toEqual(mockUsers);
    });
  });

  describe('useResources', () => {
    it('fetches resources', async () => {
      const mockResources = [
        { id: 1, name: 'Resource 1', type: 'equipment' },
        { id: 2, name: 'Resource 2', type: 'room' },
      ];
      vi.mocked(apiClient.get).mockResolvedValue({ data: mockResources });

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

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

      expect(apiClient.get).toHaveBeenCalledWith('/resources/');
      expect(result.current.data).toEqual(mockResources);
    });

    it('handles empty resources list', async () => {
      vi.mocked(apiClient.get).mockResolvedValue({ data: [] });

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

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

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

    it('handles fetch error', async () => {
      vi.mocked(apiClient.get).mockRejectedValue(new Error('Network error'));

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

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

      expect(result.current.error).toBeDefined();
    });
  });

  describe('useCreateResource', () => {
    it('creates a resource', async () => {
      const mockResource = { id: 3, name: 'New Resource', type: 'equipment' };
      vi.mocked(apiClient.post).mockResolvedValue({ data: mockResource });

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

      await act(async () => {
        const data = await result.current.mutateAsync({ name: 'New Resource', type: 'equipment' });
        expect(data).toEqual(mockResource);
      });

      expect(apiClient.post).toHaveBeenCalledWith('/resources/', {
        name: 'New Resource',
        type: 'equipment',
      });
    });

    it('creates a resource with user_id', async () => {
      const mockResource = { id: 4, name: 'Staff Resource', type: 'staff', user_id: 'user-123' };
      vi.mocked(apiClient.post).mockResolvedValue({ data: mockResource });

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

      await act(async () => {
        await result.current.mutateAsync({ name: 'Staff Resource', type: 'staff', user_id: 'user-123' });
      });

      expect(apiClient.post).toHaveBeenCalledWith('/resources/', {
        name: 'Staff Resource',
        type: 'staff',
        user_id: 'user-123',
      });
    });

    it('handles creation error', async () => {
      vi.mocked(apiClient.post).mockRejectedValue(new Error('Validation failed'));

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

      await expect(
        act(async () => {
          await result.current.mutateAsync({ name: '', type: 'equipment' });
        })
      ).rejects.toThrow('Validation failed');
    });
  });
});
