import React from 'react';
import { render, screen, waitFor, fireEvent } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ThemeProvider } from 'styled-components';
import { MemoryRouter } from 'react-router-dom';
import { I18nextProvider } from 'react-i18next';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import '@testing-library/jest-dom';
import { NotificationBell } from '@/features/notifications/components/NotificationBell';
import * as notificationService from '@/features/notifications/services/notificationService';
import type { NotificationItem } from '@/features/notifications/types/notification.types';
import i18n from '@/locales/i18n';
import { LocaleProvider } from '@/app/providers/LocaleProvider';
import { lightTheme } from '@/styles/theme';

vi.mock('@/features/notifications/services/notificationService');

const mockNotification: NotificationItem = {
  id: 'notification-1',
  type: 'ticket_created',
  type_label: 'Ticket Created',
  icon: 'ticket',
  color: '#6366F1',
  title: 'Ticket TKT-001 was created',
  message: 'Your ticket has been submitted',
  data: { ticket_id: 'ticket-1' },
  related_type: 'App\\Modules\\Ticketing\\Models\\Ticket',
  related_id: 'ticket-1',
  is_read: false,
  read_at: null,
  created_at: '2026-05-18T10:00:00Z',
  created_at_human: '2 hours ago',
};

function renderBell() {
  const queryClient = new QueryClient({
    defaultOptions: {
      queries: { retry: false },
      mutations: { retry: false },
    },
  });

  return render(
    <QueryClientProvider client={queryClient}>
      <I18nextProvider i18n={i18n}>
        <LocaleProvider>
          <ThemeProvider theme={lightTheme}>
            <MemoryRouter>
              <NotificationBell />
            </MemoryRouter>
          </ThemeProvider>
        </LocaleProvider>
      </I18nextProvider>
    </QueryClientProvider>,
  );
}

describe('NotificationBell', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    void i18n.changeLanguage('en');
    vi.mocked(notificationService.fetchUnreadCount).mockResolvedValue(0);
    vi.mocked(notificationService.fetchNotifications).mockResolvedValue({ items: [] });
  });

  it('renders unread count in header', async () => {
    vi.mocked(notificationService.fetchUnreadCount).mockResolvedValue(5);

    renderBell();

    await waitFor(() => {
      expect(screen.getByLabelText(/5 unread notifications/i)).toHaveTextContent('5');
    });
  });

  it('shows loading state in dropdown', async () => {
    vi.mocked(notificationService.fetchNotifications).mockReturnValue(new Promise(() => {}));

    renderBell();
    fireEvent.click(screen.getByRole('button', { name: /notifications/i }));

    expect(await screen.findByText(/loading notifications/i)).toBeInTheDocument();
  });

  it('shows notifications in dropdown on success', async () => {
    vi.mocked(notificationService.fetchNotifications).mockResolvedValue({
      items: [mockNotification],
    });

    renderBell();
    fireEvent.click(screen.getByRole('button', { name: /notifications/i }));

    await waitFor(() => {
      expect(screen.getByText('Ticket TKT-001 was created')).toBeInTheDocument();
    });
  });

  it('shows empty state in dropdown', async () => {
    vi.mocked(notificationService.fetchNotifications).mockResolvedValue({ items: [] });

    renderBell();
    fireEvent.click(screen.getByRole('button', { name: /notifications/i }));

    expect(await screen.findByText(/you have no notifications yet/i)).toBeInTheDocument();
  });

  it('marks a notification as read', async () => {
    vi.mocked(notificationService.fetchNotifications).mockResolvedValue({
      items: [mockNotification],
    });
    vi.mocked(notificationService.markNotificationRead).mockResolvedValue();

    renderBell();
    fireEvent.click(screen.getByRole('button', { name: /notifications/i }));

    await waitFor(() => {
      expect(screen.getByText('Ticket TKT-001 was created')).toBeInTheDocument();
    });

    fireEvent.click(screen.getByRole('button', { name: /mark as read/i }));

    await waitFor(() => {
      expect(notificationService.markNotificationRead).toHaveBeenCalledWith('notification-1');
    });
  });

  it('marks all notifications as read', async () => {
    vi.mocked(notificationService.fetchNotifications).mockResolvedValue({
      items: [mockNotification],
    });
    vi.mocked(notificationService.markAllNotificationsRead).mockResolvedValue();

    renderBell();
    fireEvent.click(screen.getByRole('button', { name: /notifications/i }));

    await waitFor(() => {
      expect(screen.getByRole('button', { name: /mark all as read/i })).toBeInTheDocument();
    });

    fireEvent.click(screen.getByRole('button', { name: /mark all as read/i }));

    await waitFor(() => {
      expect(notificationService.markAllNotificationsRead).toHaveBeenCalled();
    });
  });
});
