import React from 'react';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';
import App from '../App';
import AuthProvider from '../context/AuthContext';

// Mock react-toastify to avoid toast errors
jest.mock('react-toastify', () => ({
  toast: {
    success: jest.fn(),
    error: jest.fn(),
    info: jest.fn(),
  },
  ToastContainer: () => null,
}));

// Mock Leaflet map components to avoid rendering issues
jest.mock('react-leaflet', () => ({
  MapContainer: ({ children }) => <div data-testid="map-container">{children}</div>,
  TileLayer: () => <div>TileLayer</div>,
  Marker: () => <div>Marker</div>,
  Popup: ({ children }) => <div>{children}</div>,
  useMap: () => ({
    flyTo: jest.fn(),
  }),
}));



// Mock EventSource for SSE
global.EventSource = jest.fn(() => ({
  addEventListener: jest.fn(),
  removeEventListener: jest.fn(),
  close: jest.fn(),
  readyState: 1,
}));

describe('Authentication Flow Integration Tests', () => {
  beforeEach(() => {
    localStorage.clear();
  });

  const renderApp = () => {
    return render(
      <BrowserRouter>
        <AuthProvider>
          <App />
        </AuthProvider>
      </BrowserRouter>
    );
  };

  describe('Registration Flow', () => {
    it('should allow user to register and access protected routes', async () => {
      renderApp();

      // Should be on the login page initially (or map if not authenticated)
      await waitFor(() => {
        expect(screen.queryByRole('status')).not.toBeInTheDocument();
      });

      // Navigate to register page if there's a link
      const registerLinks = screen.queryAllByText(/register/i);
      if (registerLinks.length > 0) {
        fireEvent.click(registerLinks[0]);
      }

      // Fill out registration form
      await waitFor(() => {
        const nameInput = screen.queryByPlaceholderText(/name/i);
        if (nameInput) {
          fireEvent.change(nameInput, { target: { value: 'Test User' } });

          const emailInput = screen.getByPlaceholderText(/email/i);
          fireEvent.change(emailInput, { target: { value: 'test@example.com' } });

          const passwordInput = screen.getByPlaceholderText(/^password$/i);
          fireEvent.change(passwordInput, { target: { value: 'password123' } });

          const confirmPasswordInput = screen.getByPlaceholderText(/confirm password/i);
          fireEvent.change(confirmPasswordInput, { target: { value: 'password123' } });

          const submitButton = screen.getByRole('button', { name: /register/i });
          fireEvent.click(submitButton);
        }
      });
    });
  });

  describe('Login Flow', () => {
    it('should allow user to login and access protected routes', async () => {
      renderApp();

      // Wait for initial loading
      await waitFor(() => {
        expect(screen.queryByRole('status')).not.toBeInTheDocument();
      }, { timeout: 3000 });

      // Look for login form
      const emailInput = screen.queryByPlaceholderText(/email/i);
      const passwordInput = screen.queryByPlaceholderText(/password/i);

      if (emailInput && passwordInput) {
        // Fill out login form
        fireEvent.change(emailInput, { target: { value: 'test@example.com' } });
        fireEvent.change(passwordInput, { target: { value: 'password123' } });

        const loginButton = screen.getByRole('button', { name: /login/i });
        fireEvent.click(loginButton);

        // Wait for login to complete
        await waitFor(() => {
          // After successful login, should redirect or show authenticated content
          expect(localStorage.getItem('token')).toBeDefined();
        }, { timeout: 3000 });
      }
    });

    it('should show error with invalid credentials', async () => {
      renderApp();

      await waitFor(() => {
        expect(screen.queryByRole('status')).not.toBeInTheDocument();
      });

      const emailInput = screen.queryByPlaceholderText(/email/i);
      const passwordInput = screen.queryByPlaceholderText(/password/i);

      if (emailInput && passwordInput) {
        fireEvent.change(emailInput, { target: { value: 'wrong@example.com' } });
        fireEvent.change(passwordInput, { target: { value: 'wrongpassword' } });

        const loginButton = screen.getByRole('button', { name: /login/i });
        fireEvent.click(loginButton);

        // Wait for error handling
        await waitFor(() => {
          expect(localStorage.getItem('token')).toBeNull();
        });
      }
    });
  });

  describe('Protected Routes', () => {
    it('should redirect unauthenticated users from protected routes', async () => {
      renderApp();

      await waitFor(() => {
        expect(screen.queryByRole('status')).not.toBeInTheDocument();
      });

      // Unauthenticated users should not have access to certain features
      // This would depend on your routing configuration
      expect(localStorage.getItem('token')).toBeNull();
    });
  });

  describe('Logout Flow', () => {
    it('should logout user and clear authentication state', async () => {
      // Set a mock token
      localStorage.setItem('token', 'mock-jwt-token');

      renderApp();

      await waitFor(() => {
        expect(screen.queryByRole('status')).not.toBeInTheDocument();
      });

      // Look for logout button/link
      const logoutButtons = screen.queryAllByText(/logout/i);

      if (logoutButtons.length > 0) {
        fireEvent.click(logoutButtons[0]);

        await waitFor(() => {
          expect(localStorage.getItem('token')).toBeNull();
        });
      }
    });
  });

  describe('Token Persistence', () => {
    it('should load user from token on app mount', async () => {
      // Set a valid token
      localStorage.setItem('token', 'mock-jwt-token');

      renderApp();

      // Should attempt to load user
      await waitFor(() => {
        expect(screen.queryByRole('status')).not.toBeInTheDocument();
      });
    });

    it('should handle invalid token on app mount', async () => {
      // Set an invalid token
      localStorage.setItem('token', 'invalid-token');

      renderApp();

      await waitFor(() => {
        expect(screen.queryByRole('status')).not.toBeInTheDocument();
      });

      // Token should be cleared if invalid
      // This depends on the error handling in AuthContext
    });
  });

  describe('Session Management', () => {
    it('should maintain authentication across page navigation', async () => {
      localStorage.setItem('token', 'mock-jwt-token');

      renderApp();

      await waitFor(() => {
        expect(screen.queryByRole('status')).not.toBeInTheDocument();
      });

      // Token should persist
      expect(localStorage.getItem('token')).toBe('mock-jwt-token');
    });
  });
});
