import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { EventList } from '../event-list';
import { api } from '@/lib/api';

// Mock the API
jest.mock('@/lib/api', () => ({
  api: {
    getEvents: jest.fn(),
  },
  Event: {},
}));

describe('EventList', () => {
  const mockEvents = [
    {
      id: '1',
      name: 'Marathon 2024',
      description: 'Annual city marathon',
      eventDate: '2024-06-15',
      location: 'City Center',
      status: 'Published',
      category: 'Running',
      tags: ['marathon', 'running'],
      maxParticipants: 100,
      currentRegistrations: 45,
    },
    {
      id: '2',
      name: 'Cycling Race',
      description: 'Mountain cycling event',
      eventDate: '2024-07-20',
      location: 'Mountain Trail',
      status: 'Draft',
      category: 'Cycling',
      tags: ['cycling', 'mountain'],
      maxParticipants: 50,
      currentRegistrations: 20,
    },
  ];

  beforeEach(() => {
    jest.clearAllMocks();
  });

  // Positive Tests
  describe('Positive Tests', () => {
    it('renders loading state initially', () => {
      (api.getEvents as jest.Mock).mockImplementation(() => new Promise(() => {}));
      
      render(<EventList />);
      
      expect(screen.getByText(/loading events/i)).toBeInTheDocument();
    });

    it('renders list of events', async () => {
      (api.getEvents as jest.Mock).mockResolvedValue(mockEvents);
      
      render(<EventList />);
      
      await waitFor(() => {
        expect(screen.getByText('Marathon 2024')).toBeInTheDocument();
      });
      
      expect(screen.getByText('Cycling Race')).toBeInTheDocument();
      expect(screen.getByText('Annual city marathon')).toBeInTheDocument();
    });

    it('filters events by category', async () => {
      (api.getEvents as jest.Mock).mockResolvedValue([mockEvents[0]]);
      
      render(<EventList />);
      
      await waitFor(() => {
        expect(screen.queryByText(/loading/i)).not.toBeInTheDocument();
      });
      
      fireEvent.change(screen.getByLabelText(/category/i), {
        target: { value: 'Running' },
      });
      
      await waitFor(() => {
        expect(api.getEvents).toHaveBeenCalledWith(expect.objectContaining({ category: 'Running' }));
      });
    });

    it('filters events by status', async () => {
      (api.getEvents as jest.Mock).mockResolvedValue([mockEvents[1]]);
      
      render(<EventList />);
      
      await waitFor(() => {
        expect(screen.queryByText(/loading/i)).not.toBeInTheDocument();
      });
      
      fireEvent.change(screen.getByLabelText(/status/i), {
        target: { value: 'Draft' },
      });
      
      await waitFor(() => {
        expect(api.getEvents).toHaveBeenCalledWith(expect.objectContaining({ status: 'Draft' }));
      });
    });

    it('displays event details correctly', async () => {
      (api.getEvents as jest.Mock).mockResolvedValue([mockEvents[0]]);
      
      render(<EventList />);
      
      await waitFor(() => {
        expect(screen.getByText('Marathon 2024')).toBeInTheDocument();
      });
      
      expect(screen.getByText('City Center')).toBeInTheDocument();
      expect(screen.getByText(/45.*\/.*100.*registered/i)).toBeInTheDocument();
    });

    it('shows view details link for events', async () => {
      (api.getEvents as jest.Mock).mockResolvedValue([mockEvents[0]]);
      
      render(<EventList />);
      
      await waitFor(() => {
        expect(screen.getByText('Marathon 2024')).toBeInTheDocument();
      });
      
      const viewLink = screen.getByRole('link', { name: /view details/i });
      expect(viewLink).toHaveAttribute('href', '/events/1');
    });
  });

  // Negative Tests
  describe('Negative Tests', () => {
    it('displays error message when API fails', async () => {
      (api.getEvents as jest.Mock).mockRejectedValue(new Error('Failed to fetch'));
      
      render(<EventList />);
      
      await waitFor(() => {
        expect(screen.getByText(/failed to load events/i)).toBeInTheDocument();
      });
    });

    it('shows empty state when no events', async () => {
      (api.getEvents as jest.Mock).mockResolvedValue([]);
      
      render(<EventList />);
      
      await waitFor(() => {
        expect(screen.getByText(/no events found/i)).toBeInTheDocument();
      });
    });

    it('handles network error gracefully', async () => {
      (api.getEvents as jest.Mock).mockRejectedValue(new Error('Network error'));
      
      render(<EventList />);
      
      await waitFor(() => {
        expect(screen.getByText(/network error/i)).toBeInTheDocument();
      });
    });
  });
});
