import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { RegisterForm } from '../register-form';
import { useAuth } from '@/lib/auth-context';
import { useRouter } from 'next/navigation';

// Mock the auth context
jest.mock('@/lib/auth-context', () => ({
  useAuth: jest.fn(),
}));

// Mock next/navigation
jest.mock('next/navigation', () => ({
  useRouter: jest.fn(),
}));

describe('RegisterForm', () => {
  const mockRegister = jest.fn();
  const mockPush = jest.fn();

  beforeEach(() => {
    jest.clearAllMocks();
    (useAuth as jest.Mock).mockReturnValue({
      register: mockRegister,
      error: null,
    });
    (useRouter as jest.Mock).mockReturnValue({
      push: mockPush,
    });
  });

  // Positive Tests
  describe('Positive Tests', () => {
    it('renders registration form with all fields', () => {
      render(<RegisterForm />);
      
      expect(screen.getByLabelText(/full name/i)).toBeInTheDocument();
      expect(screen.getByLabelText(/email/i)).toBeInTheDocument();
      expect(screen.getByLabelText(/^password$/i)).toBeInTheDocument();
      expect(screen.getByLabelText(/confirm password/i)).toBeInTheDocument();
      expect(screen.getByLabelText(/account type/i)).toBeInTheDocument();
      expect(screen.getByRole('button', { name: /register/i })).toBeInTheDocument();
    });

    it('submits form with valid data', async () => {
      mockRegister.mockResolvedValueOnce(undefined);
      
      render(<RegisterForm />);
      
      fireEvent.change(screen.getByLabelText(/full name/i), {
        target: { value: 'John Doe' },
      });
      fireEvent.change(screen.getByLabelText(/email/i), {
        target: { value: 'john@example.com' },
      });
      fireEvent.change(screen.getByLabelText(/^password$/i), {
        target: { value: 'password123' },
      });
      fireEvent.change(screen.getByLabelText(/confirm password/i), {
        target: { value: 'password123' },
      });
      
      fireEvent.click(screen.getByRole('button', { name: /register/i }));
      
      await waitFor(() => {
        expect(mockRegister).toHaveBeenCalledWith('john@example.com', 'password123', 'John Doe', 'Participant');
      });
      
      await waitFor(() => {
        expect(mockPush).toHaveBeenCalledWith('/dashboard');
      });
    });

    it('allows selecting organizer role', async () => {
      mockRegister.mockResolvedValueOnce(undefined);
      
      render(<RegisterForm />);
      
      fireEvent.change(screen.getByLabelText(/full name/i), {
        target: { value: 'Jane Doe' },
      });
      fireEvent.change(screen.getByLabelText(/email/i), {
        target: { value: 'jane@example.com' },
      });
      fireEvent.change(screen.getByLabelText(/^password$/i), {
        target: { value: 'password123' },
      });
      fireEvent.change(screen.getByLabelText(/confirm password/i), {
        target: { value: 'password123' },
      });
      fireEvent.change(screen.getByLabelText(/account type/i), {
        target: { value: 'Organizer' },
      });
      
      fireEvent.click(screen.getByRole('button', { name: /register/i }));
      
      await waitFor(() => {
        expect(mockRegister).toHaveBeenCalledWith('jane@example.com', 'password123', 'Jane Doe', 'Organizer');
      });
    });

    it('shows loading state while submitting', async () => {
      mockRegister.mockImplementation(() => new Promise(() => {}));
      
      render(<RegisterForm />);
      
      fireEvent.change(screen.getByLabelText(/full name/i), {
        target: { value: 'Test User' },
      });
      fireEvent.change(screen.getByLabelText(/email/i), {
        target: { value: 'test@example.com' },
      });
      fireEvent.change(screen.getByLabelText(/^password$/i), {
        target: { value: 'password123' },
      });
      fireEvent.change(screen.getByLabelText(/confirm password/i), {
        target: { value: 'password123' },
      });
      
      fireEvent.click(screen.getByRole('button', { name: /register/i }));
      
      expect(screen.getByText(/registering/i)).toBeInTheDocument();
      expect(screen.getByRole('button', { name: /registering/i })).toBeDisabled();
    });
  });

  // Negative Tests
  describe('Negative Tests', () => {
    it('shows error when passwords do not match', async () => {
      render(<RegisterForm />);
      
      fireEvent.change(screen.getByLabelText(/full name/i), {
        target: { value: 'Test User' },
      });
      fireEvent.change(screen.getByLabelText(/email/i), {
        target: { value: 'test@example.com' },
      });
      fireEvent.change(screen.getByLabelText(/^password$/i), {
        target: { value: 'password123' },
      });
      fireEvent.change(screen.getByLabelText(/confirm password/i), {
        target: { value: 'differentpassword' },
      });
      
      fireEvent.click(screen.getByRole('button', { name: /register/i }));
      
      await waitFor(() => {
        expect(screen.getByText(/passwords do not match/i)).toBeInTheDocument();
      });
      
      expect(mockRegister).not.toHaveBeenCalled();
    });

    it('shows error when password is too short', async () => {
      render(<RegisterForm />);
      
      fireEvent.change(screen.getByLabelText(/full name/i), {
        target: { value: 'Test User' },
      });
      fireEvent.change(screen.getByLabelText(/email/i), {
        target: { value: 'test@example.com' },
      });
      fireEvent.change(screen.getByLabelText(/^password$/i), {
        target: { value: 'short' },
      });
      fireEvent.change(screen.getByLabelText(/confirm password/i), {
        target: { value: 'short' },
      });
      
      fireEvent.click(screen.getByRole('button', { name: /register/i }));
      
      await waitFor(() => {
        expect(screen.getByText(/password must be at least 8 characters/i)).toBeInTheDocument();
      });
      
      expect(mockRegister).not.toHaveBeenCalled();
    });

    it('displays error message from auth context', () => {
      (useAuth as jest.Mock).mockReturnValue({
        register: mockRegister,
        error: 'Email already exists',
      });
      
      render(<RegisterForm />);
      
      expect(screen.getByText(/email already exists/i)).toBeInTheDocument();
    });

    it('handles registration failure gracefully', async () => {
      mockRegister.mockRejectedValueOnce(new Error('Registration failed'));
      
      render(<RegisterForm />);
      
      fireEvent.change(screen.getByLabelText(/full name/i), {
        target: { value: 'Test User' },
      });
      fireEvent.change(screen.getByLabelText(/email/i), {
        target: { value: 'test@example.com' },
      });
      fireEvent.change(screen.getByLabelText(/^password$/i), {
        target: { value: 'password123' },
      });
      fireEvent.change(screen.getByLabelText(/confirm password/i), {
        target: { value: 'password123' },
      });
      
      fireEvent.click(screen.getByRole('button', { name: /register/i }));
      
      await waitFor(() => {
        expect(mockPush).not.toHaveBeenCalled();
      });
    });
  });
});
