/**
 * 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('Village Share')).toBeInTheDocument();
    });

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

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

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

      expect(screen.getByPlaceholderText('Search items...')).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 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 />);

      // There are two login buttons (mobile + desktop)
      const loginButtons = screen.getAllByRole('button', { name: 'Login or Sign Up' });
      expect(loginButtons.length).toBeGreaterThan(0);
    });

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

      // Click the first login button (either mobile or desktop)
      const loginButtons = screen.getAllByRole('button', { name: 'Login or Sign Up' });
      fireEvent.click(loginButtons[0]);

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

    it('should show Forum link when logged out', () => {
      renderWithRouter(<Navbar />);

      // There are two Forum links (mobile + desktop), both should link to /forum
      const forumLinks = screen.getAllByRole('link', { name: /Forum/i });
      expect(forumLinks.length).toBeGreaterThan(0);
      forumLinks.forEach(link => {
        expect(link).toHaveAttribute('href', '/forum');
      });
    });

    it('should show hamburger icon for mobile toggle when logged out', () => {
      renderWithRouter(<Navbar />);

      const hamburgerIcon = document.querySelector('.bi-list');
      expect(hamburgerIcon).toBeInTheDocument();
    });
  });

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

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

      // Avatar displays user initials (JD for John Doe) - may appear multiple times (mobile + desktop)
      expect(screen.getAllByText('JD').length).toBeGreaterThan(0);
    });

    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('Mobile Navigation', () => {
    it('should render mobile toggle button', () => {
      renderWithRouter(<Navbar />);

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

    it('should show avatar in mobile toggle when logged in', () => {
      mockUser = {
        id: 'user-123',
        firstName: 'John',
        lastName: 'Doe',
        email: 'john@example.com',
      };

      renderWithRouter(<Navbar />);

      // Should have avatar with initials, not hamburger icon
      expect(screen.getAllByText('JD').length).toBeGreaterThan(0);
      expect(document.querySelector('.bi-list')).not.toBeInTheDocument();
    });
  });
});
