/**
 * Navbar Component Tests
 *
 * Tests for the Navbar component including navigation links,
 * user authentication state, search functionality, and notifications.
 */

import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';
import Navbar from '../../components/Navbar';
import { rentalAPI, messageAPI } from '../../services/api';

// Mock dependencies
jest.mock('../../services/api', () => ({
  rentalAPI: {
    getPendingRequestsCount: jest.fn(),
  },
  messageAPI: {
    getUnreadCount: jest.fn(),
  },
}));

// Mock socket context
jest.mock('../../contexts/SocketContext', () => ({
  useSocket: () => ({
    onNewMessage: jest.fn(() => () => {}),
    onMessageRead: jest.fn(() => () => {}),
  }),
}));

// Variable to control auth state per test
let mockUser: any = null;
const mockLogout = jest.fn();
const mockOpenAuthModal = jest.fn();

jest.mock('../../contexts/AuthContext', () => ({
  useAuth: () => ({
    user: mockUser,
    logout: mockLogout,
    openAuthModal: mockOpenAuthModal,
  }),
}));

// Mock useNavigate
const mockNavigate = jest.fn();
jest.mock('react-router-dom', () => ({
  ...jest.requireActual('react-router-dom'),
  useNavigate: () => mockNavigate,
}));

// Helper to render with Router
const renderWithRouter = (component: React.ReactElement) => {
  return render(<BrowserRouter>{component}</BrowserRouter>);
};

describe('Navbar', () => {
  beforeEach(() => {
    jest.clearAllMocks();
    mockUser = null;

    // Default mock implementations
    (rentalAPI.getPendingRequestsCount as jest.Mock).mockResolvedValue({ data: { count: 0 } });
    (messageAPI.getUnreadCount as jest.Mock).mockResolvedValue({ data: { count: 0 } });
  });

  describe('Branding', () => {
    it('should display the brand name', () => {
      renderWithRouter(<Navbar />);

      expect(screen.getByText('CommunityRentals.App')).toBeInTheDocument();
    });

    it('should link brand to home page', () => {
      renderWithRouter(<Navbar />);

      const brandLink = screen.getByRole('link', { name: /CommunityRentals.App/i });
      expect(brandLink).toHaveAttribute('href', '/');
    });
  });

  describe('Search Functionality', () => {
    it('should render search input', () => {
      renderWithRouter(<Navbar />);

      expect(screen.getByPlaceholderText('Search items...')).toBeInTheDocument();
    });

    it('should render location input', () => {
      renderWithRouter(<Navbar />);

      expect(screen.getByPlaceholderText('City or ZIP')).toBeInTheDocument();
    });

    it('should render search button', () => {
      renderWithRouter(<Navbar />);

      // Search button has an icon
      const searchButton = document.querySelector('.bi-search');
      expect(searchButton).toBeInTheDocument();
    });

    it('should navigate to items page when search is submitted', () => {
      renderWithRouter(<Navbar />);

      const searchInput = screen.getByPlaceholderText('Search items...');
      fireEvent.change(searchInput, { target: { value: 'camera' } });

      const searchButton = document.querySelector('button.btn-outline-secondary') as HTMLButtonElement;
      fireEvent.click(searchButton);

      expect(mockNavigate).toHaveBeenCalledWith('/items?search=camera');
    });

    it('should handle Enter key in search input', () => {
      renderWithRouter(<Navbar />);

      const searchInput = screen.getByPlaceholderText('Search items...');
      fireEvent.change(searchInput, { target: { value: 'tent' } });
      fireEvent.keyDown(searchInput, { key: 'Enter' });

      expect(mockNavigate).toHaveBeenCalledWith('/items?search=tent');
    });

    it('should append city to search URL', () => {
      renderWithRouter(<Navbar />);

      const searchInput = screen.getByPlaceholderText('Search items...');
      const locationInput = screen.getByPlaceholderText('City or ZIP');

      fireEvent.change(searchInput, { target: { value: 'kayak' } });
      fireEvent.change(locationInput, { target: { value: 'Seattle' } });

      const searchButton = document.querySelector('button.btn-outline-secondary') as HTMLButtonElement;
      fireEvent.click(searchButton);

      expect(mockNavigate).toHaveBeenCalledWith('/items?search=kayak&city=Seattle');
    });

    it('should append zipCode when location is a zip code', () => {
      renderWithRouter(<Navbar />);

      const searchInput = screen.getByPlaceholderText('Search items...');
      const locationInput = screen.getByPlaceholderText('City or ZIP');

      fireEvent.change(searchInput, { target: { value: 'bike' } });
      fireEvent.change(locationInput, { target: { value: '98101' } });

      const searchButton = document.querySelector('button.btn-outline-secondary') as HTMLButtonElement;
      fireEvent.click(searchButton);

      expect(mockNavigate).toHaveBeenCalledWith('/items?search=bike&zipCode=98101');
    });

    it('should clear search fields after search', () => {
      renderWithRouter(<Navbar />);

      const searchInput = screen.getByPlaceholderText('Search items...') as HTMLInputElement;
      fireEvent.change(searchInput, { target: { value: 'camera' } });

      const searchButton = document.querySelector('button.btn-outline-secondary') as HTMLButtonElement;
      fireEvent.click(searchButton);

      expect(searchInput.value).toBe('');
    });
  });

  describe('Logged Out State', () => {
    it('should show login button when user is not logged in', () => {
      renderWithRouter(<Navbar />);

      expect(screen.getByRole('button', { name: 'Login or Sign Up' })).toBeInTheDocument();
    });

    it('should call openAuthModal when login button is clicked', () => {
      renderWithRouter(<Navbar />);

      fireEvent.click(screen.getByRole('button', { name: 'Login or Sign Up' }));

      expect(mockOpenAuthModal).toHaveBeenCalledWith('login');
    });
  });

  describe('Logged In State', () => {
    beforeEach(() => {
      mockUser = {
        id: 'user-123',
        firstName: 'John',
        lastName: 'Doe',
        email: 'john@example.com',
      };
    });

    it('should show user name when logged in', () => {
      renderWithRouter(<Navbar />);

      expect(screen.getByText('John')).toBeInTheDocument();
    });

    it('should not show login button when logged in', () => {
      renderWithRouter(<Navbar />);

      expect(screen.queryByRole('button', { name: 'Login or Sign Up' })).not.toBeInTheDocument();
    });

    it('should show profile link in dropdown', () => {
      renderWithRouter(<Navbar />);

      expect(screen.getByRole('link', { name: /Profile/i })).toHaveAttribute('href', '/profile');
    });

    it('should show renting link in dropdown', () => {
      renderWithRouter(<Navbar />);

      expect(screen.getByRole('link', { name: /Renting/i })).toHaveAttribute('href', '/renting');
    });

    it('should show owning link in dropdown', () => {
      renderWithRouter(<Navbar />);

      expect(screen.getByRole('link', { name: /Owning/i })).toHaveAttribute('href', '/owning');
    });

    it('should show messages link in dropdown', () => {
      renderWithRouter(<Navbar />);

      expect(screen.getByRole('link', { name: /Messages/i })).toHaveAttribute('href', '/messages');
    });

    it('should show forum link in dropdown', () => {
      renderWithRouter(<Navbar />);

      expect(screen.getByRole('link', { name: /Forum/i })).toHaveAttribute('href', '/forum');
    });

    it('should show earnings link in dropdown', () => {
      renderWithRouter(<Navbar />);

      expect(screen.getByRole('link', { name: /Earnings/i })).toHaveAttribute('href', '/earnings');
    });

    it('should call logout and navigate home when logout is clicked', () => {
      renderWithRouter(<Navbar />);

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

      expect(mockLogout).toHaveBeenCalled();
      expect(mockNavigate).toHaveBeenCalledWith('/');
    });
  });

  describe('Start Earning Link', () => {
    it('should show Start Earning link', () => {
      renderWithRouter(<Navbar />);

      expect(screen.getByRole('link', { name: 'Start Earning' })).toHaveAttribute('href', '/create-item');
    });
  });

  describe('Mobile Navigation', () => {
    it('should render mobile toggle button', () => {
      renderWithRouter(<Navbar />);

      expect(screen.getByLabelText('Toggle navigation')).toBeInTheDocument();
    });
  });
});
