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 the notifications API
vi.mock('../../api/notifications', () => ({
  getNotifications: vi.fn(),
  getUnreadCount: vi.fn(),
  markNotificationRead: vi.fn(),
  markAllNotificationsRead: vi.fn(),
  clearAllNotifications: vi.fn(),
}));

import {
  useNotifications,
  useUnreadNotificationCount,
  useMarkNotificationRead,
  useMarkAllNotificationsRead,
  useClearAllNotifications,
} from '../useNotifications';
import * as notificationsApi from '../../api/notifications';

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

  describe('useNotifications', () => {
    it('fetches notifications', async () => {
      const mockNotifications = [
        { id: 1, verb: 'created', read: false, timestamp: '2024-01-01T00:00:00Z' },
      ];
      vi.mocked(notificationsApi.getNotifications).mockResolvedValue(mockNotifications);

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

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

      expect(notificationsApi.getNotifications).toHaveBeenCalledWith(undefined);
      expect(result.current.data).toEqual(mockNotifications);
    });

    it('passes options to API', async () => {
      vi.mocked(notificationsApi.getNotifications).mockResolvedValue([]);

      renderHook(() => useNotifications({ read: false, limit: 10 }), {
        wrapper: createWrapper(),
      });

      await waitFor(() => {
        expect(notificationsApi.getNotifications).toHaveBeenCalledWith({
          read: false,
          limit: 10,
        });
      });
    });
  });

  describe('useUnreadNotificationCount', () => {
    it('fetches unread count', async () => {
      vi.mocked(notificationsApi.getUnreadCount).mockResolvedValue(5);

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

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

      expect(result.current.data).toBe(5);
    });
  });

  describe('useMarkNotificationRead', () => {
    it('marks notification as read', async () => {
      vi.mocked(notificationsApi.markNotificationRead).mockResolvedValue(undefined);

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

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

      expect(notificationsApi.markNotificationRead).toHaveBeenCalled();
      expect(vi.mocked(notificationsApi.markNotificationRead).mock.calls[0][0]).toBe(42);
    });
  });

  describe('useMarkAllNotificationsRead', () => {
    it('marks all notifications as read', async () => {
      vi.mocked(notificationsApi.markAllNotificationsRead).mockResolvedValue(undefined);

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

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

      expect(notificationsApi.markAllNotificationsRead).toHaveBeenCalled();
    });
  });

  describe('useClearAllNotifications', () => {
    it('clears all notifications', async () => {
      vi.mocked(notificationsApi.clearAllNotifications).mockResolvedValue(undefined);

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

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

      expect(notificationsApi.clearAllNotifications).toHaveBeenCalled();
    });
  });
});
