/**
 * Unit tests for NotFound component
 *
 * Tests cover:
 * - Component rendering
 * - 404 message display
 * - Navigation links (Go Home, Go Back, Contact Support)
 * - Illustration/icon rendering
 * - Accessibility features
 * - Internationalization (i18n)
 * - Button interactions
 * - Responsive design elements
 * - Dark mode styling classes
 */

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { BrowserRouter } from 'react-router-dom';
import React from 'react';
import NotFound from '../NotFound';

// Mock react-router-dom's useNavigate
const mockNavigate = vi.fn();
vi.mock('react-router-dom', async () => {
  const actual = await vi.importActual('react-router-dom');
  return {
    ...actual,
    useNavigate: () => mockNavigate,
  };
});

// Mock react-i18next
vi.mock('react-i18next', () => ({
  useTranslation: () => ({
    t: (key: string, fallback?: string) => {
      const translations: Record<string, string> = {
        'errors.pageNotFound': 'Page Not Found',
        'errors.pageNotFoundDescription': 'The page you are looking for does not exist or has been moved.',
        'navigation.goHome': 'Go Home',
        'navigation.goBack': 'Go Back',
        'errors.needHelp': 'Need help?',
        'navigation.contactSupport': 'Contact Support',
      };
      return translations[key] || fallback || key;
    },
  }),
}));

// Test wrapper with Router
const createWrapper = () => {
  return ({ children }: { children: React.ReactNode }) => (
    <BrowserRouter>{children}</BrowserRouter>
  );
};

describe('NotFound', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe('Rendering', () => {
    it('should render the NotFound component', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      expect(screen.getByText('Page Not Found')).toBeInTheDocument();
    });

    it('should render within a centered container', () => {
      const { container } = render(<NotFound />, { wrapper: createWrapper() });

      const mainDiv = container.querySelector('.min-h-screen');
      expect(mainDiv).toBeInTheDocument();
      expect(mainDiv).toHaveClass('flex', 'items-center', 'justify-center');
    });

    it('should render all main sections', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      // Title
      expect(screen.getByText('Page Not Found')).toBeInTheDocument();

      // Description
      expect(screen.getByText(/the page you are looking for does not exist/i)).toBeInTheDocument();

      // Navigation buttons
      expect(screen.getByRole('link', { name: /go home/i })).toBeInTheDocument();
      expect(screen.getByRole('button', { name: /go back/i })).toBeInTheDocument();

      // Support link
      expect(screen.getByRole('link', { name: /contact support/i })).toBeInTheDocument();
    });
  });

  describe('404 Message Display', () => {
    it('should display the 404 error code', () => {
      render(<NotFound />, { wrapper: createWrapper() });

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

    it('should display "Page Not Found" heading', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      const heading = screen.getByRole('heading', { level: 1 });
      expect(heading).toHaveTextContent('Page Not Found');
    });

    it('should display error description', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      expect(screen.getByText(/the page you are looking for does not exist or has been moved/i)).toBeInTheDocument();
    });

    it('should apply correct heading styles', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      const heading = screen.getByRole('heading', { level: 1 });
      expect(heading).toHaveClass('text-3xl', 'font-bold', 'text-gray-900', 'dark:text-white');
    });

    it('should apply correct description styles', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      const description = screen.getByText(/the page you are looking for does not exist or has been moved/i);
      expect(description).toHaveClass('text-lg', 'text-gray-600', 'dark:text-gray-400');
    });
  });

  describe('Navigation Links', () => {
    it('should render "Go Home" link with correct href', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      const homeLink = screen.getByRole('link', { name: /go home/i });
      expect(homeLink).toHaveAttribute('href', '/');
    });

    it('should render "Go Back" button', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      const backButton = screen.getByRole('button', { name: /go back/i });
      expect(backButton).toBeInTheDocument();
    });

    it('should render "Contact Support" link with correct href', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      const supportLink = screen.getByRole('link', { name: /contact support/i });
      expect(supportLink).toHaveAttribute('href', '/support');
    });

    it('should display Home icon in "Go Home" link', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      const homeLink = screen.getByRole('link', { name: /go home/i });
      const icon = homeLink.querySelector('svg');
      expect(icon).toBeInTheDocument();
    });

    it('should display ArrowLeft icon in "Go Back" button', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      const backButton = screen.getByRole('button', { name: /go back/i });
      const icon = backButton.querySelector('svg');
      expect(icon).toBeInTheDocument();
    });

    it('should call navigate(-1) when "Go Back" is clicked', async () => {
      const user = userEvent.setup();
      render(<NotFound />, { wrapper: createWrapper() });

      const backButton = screen.getByRole('button', { name: /go back/i });
      await user.click(backButton);

      expect(mockNavigate).toHaveBeenCalledWith(-1);
    });

    it('should call navigate(-1) only once per click', async () => {
      const user = userEvent.setup();
      render(<NotFound />, { wrapper: createWrapper() });

      const backButton = screen.getByRole('button', { name: /go back/i });
      await user.click(backButton);

      expect(mockNavigate).toHaveBeenCalledTimes(1);
    });
  });

  describe('Illustration Rendering', () => {
    it('should render the FileQuestion illustration', () => {
      const { container } = render(<NotFound />, { wrapper: createWrapper() });

      // Check for FileQuestion icon (lucide-react renders as SVG)
      const illustrations = container.querySelectorAll('svg');
      expect(illustrations.length).toBeGreaterThan(0);
    });

    it('should display 404 text overlaid on illustration', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      const errorCode = screen.getByText('404');
      expect(errorCode).toBeInTheDocument();
      expect(errorCode).toHaveClass('text-6xl', 'font-bold');
    });

    it('should have correct illustration container classes', () => {
      const { container } = render(<NotFound />, { wrapper: createWrapper() });

      const illustrationContainer = container.querySelector('.relative');
      expect(illustrationContainer).toBeInTheDocument();
    });

    it('should apply correct styles to FileQuestion icon', () => {
      const { container } = render(<NotFound />, { wrapper: createWrapper() });

      // FileQuestion icon should have specific classes
      const iconContainer = container.querySelector('.text-gray-300.dark\\:text-gray-700');
      expect(iconContainer).toBeInTheDocument();
    });
  });

  describe('Button Styling', () => {
    it('should apply primary button styles to "Go Home" link', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      const homeLink = screen.getByRole('link', { name: /go home/i });
      expect(homeLink).toHaveClass(
        'bg-blue-600',
        'text-white',
        'hover:bg-blue-700',
        'rounded-lg'
      );
    });

    it('should apply secondary button styles to "Go Back" button', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      const backButton = screen.getByRole('button', { name: /go back/i });
      expect(backButton).toHaveClass(
        'bg-gray-200',
        'text-gray-700',
        'hover:bg-gray-300',
        'rounded-lg'
      );
    });

    it('should apply dark mode styles to "Go Back" button', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      const backButton = screen.getByRole('button', { name: /go back/i });
      expect(backButton).toHaveClass(
        'dark:bg-gray-700',
        'dark:text-gray-200',
        'dark:hover:bg-gray-600'
      );
    });

    it('should have transition classes on buttons', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      const homeLink = screen.getByRole('link', { name: /go home/i });
      const backButton = screen.getByRole('button', { name: /go back/i });

      expect(homeLink).toHaveClass('transition-colors');
      expect(backButton).toHaveClass('transition-colors');
    });
  });

  describe('Accessibility', () => {
    it('should have proper heading hierarchy', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      const heading = screen.getByRole('heading', { level: 1 });
      expect(heading).toBeInTheDocument();
    });

    it('should have aria-hidden on decorative icons', () => {
      const { container } = render(<NotFound />, { wrapper: createWrapper() });

      const icons = container.querySelectorAll('[aria-hidden="true"]');
      expect(icons.length).toBeGreaterThan(0);
    });

    it('should have focus styles on "Go Home" link', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      const homeLink = screen.getByRole('link', { name: /go home/i });
      expect(homeLink).toHaveClass('focus:outline-none', 'focus:ring-2', 'focus:ring-blue-500');
    });

    it('should have focus styles on "Go Back" button', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      const backButton = screen.getByRole('button', { name: /go back/i });
      expect(backButton).toHaveClass('focus:outline-none', 'focus:ring-2', 'focus:ring-gray-500');
    });

    it('should be keyboard accessible', async () => {
      const user = userEvent.setup();
      render(<NotFound />, { wrapper: createWrapper() });

      const homeLink = screen.getByRole('link', { name: /go home/i });
      const backButton = screen.getByRole('button', { name: /go back/i });

      // Tab to home link
      await user.tab();
      expect(homeLink).toHaveFocus();

      // Tab to back button
      await user.tab();
      expect(backButton).toHaveFocus();
    });

    it('should support Enter key on "Go Back" button', async () => {
      const user = userEvent.setup();
      render(<NotFound />, { wrapper: createWrapper() });

      const backButton = screen.getByRole('button', { name: /go back/i });
      backButton.focus();
      await user.keyboard('{Enter}');

      expect(mockNavigate).toHaveBeenCalledWith(-1);
    });

    it('should have accessible link text', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      expect(screen.getByRole('link', { name: /go home/i })).toHaveAccessibleName();
      expect(screen.getByRole('button', { name: /go back/i })).toHaveAccessibleName();
      expect(screen.getByRole('link', { name: /contact support/i })).toHaveAccessibleName();
    });
  });

  describe('Responsive Design', () => {
    it('should have responsive flex classes on button container', () => {
      const { container } = render(<NotFound />, { wrapper: createWrapper() });

      const buttonContainer = container.querySelector('.flex.flex-col.sm\\:flex-row');
      expect(buttonContainer).toBeInTheDocument();
    });

    it('should have responsive padding on main container', () => {
      const { container } = render(<NotFound />, { wrapper: createWrapper() });

      const mainContainer = container.querySelector('.px-4.py-16');
      expect(mainContainer).toBeInTheDocument();
    });

    it('should have max-width constraint on content', () => {
      const { container } = render(<NotFound />, { wrapper: createWrapper() });

      const contentContainer = container.querySelector('.max-w-md.w-full');
      expect(contentContainer).toBeInTheDocument();
    });
  });

  describe('Dark Mode Support', () => {
    it('should have dark mode background class', () => {
      const { container } = render(<NotFound />, { wrapper: createWrapper() });

      const mainDiv = container.querySelector('.bg-gray-50.dark\\:bg-gray-900');
      expect(mainDiv).toBeInTheDocument();
    });

    it('should have dark mode text classes on heading', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      const heading = screen.getByRole('heading', { level: 1 });
      expect(heading).toHaveClass('dark:text-white');
    });

    it('should have dark mode text classes on description', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      const description = screen.getByText(/the page you are looking for does not exist or has been moved/i);
      expect(description).toHaveClass('dark:text-gray-400');
    });

    it('should have dark mode focus ring offset on buttons', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      const homeLink = screen.getByRole('link', { name: /go home/i });
      const backButton = screen.getByRole('button', { name: /go back/i });

      expect(homeLink).toHaveClass('dark:focus:ring-offset-gray-900');
      expect(backButton).toHaveClass('dark:focus:ring-offset-gray-900');
    });
  });

  describe('Internationalization', () => {
    it('should use translation for page title', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      expect(screen.getByText('Page Not Found')).toBeInTheDocument();
    });

    it('should use translation for error description', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      expect(screen.getByText('The page you are looking for does not exist or has been moved.')).toBeInTheDocument();
    });

    it('should use translation for "Go Home" button', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      expect(screen.getByText('Go Home')).toBeInTheDocument();
    });

    it('should use translation for "Go Back" button', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      expect(screen.getByText('Go Back')).toBeInTheDocument();
    });

    it('should use translation for help text', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      expect(screen.getByText('Need help?')).toBeInTheDocument();
    });

    it('should use translation for support link', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      expect(screen.getByText('Contact Support')).toBeInTheDocument();
    });
  });

  describe('Support Section', () => {
    it('should render help text', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      expect(screen.getByText('Need help?')).toBeInTheDocument();
    });

    it('should render contact support link', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      const supportLink = screen.getByRole('link', { name: /contact support/i });
      expect(supportLink).toBeInTheDocument();
      expect(supportLink).toHaveAttribute('href', '/support');
    });

    it('should style support link correctly', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      const supportLink = screen.getByRole('link', { name: /contact support/i });
      expect(supportLink).toHaveClass('text-blue-600', 'hover:text-blue-700', 'underline');
    });

    it('should have dark mode styles on support link', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      const supportLink = screen.getByRole('link', { name: /contact support/i });
      expect(supportLink).toHaveClass('dark:text-blue-400', 'dark:hover:text-blue-300');
    });

    it('should display help text in smaller font', () => {
      const { container } = render(<NotFound />, { wrapper: createWrapper() });

      const helpText = container.querySelector('.text-sm.text-gray-500');
      expect(helpText).toBeInTheDocument();
    });
  });

  describe('Integration', () => {
    it('should render complete page structure correctly', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      // Check all main elements are present
      expect(screen.getByText('404')).toBeInTheDocument();
      expect(screen.getByRole('heading', { level: 1 })).toBeInTheDocument();
      expect(screen.getByText(/the page you are looking for does not exist/i)).toBeInTheDocument();
      expect(screen.getByRole('link', { name: /go home/i })).toBeInTheDocument();
      expect(screen.getByRole('button', { name: /go back/i })).toBeInTheDocument();
      expect(screen.getByRole('link', { name: /contact support/i })).toBeInTheDocument();
    });

    it('should handle multiple user interactions', async () => {
      const user = userEvent.setup();
      render(<NotFound />, { wrapper: createWrapper() });

      const backButton = screen.getByRole('button', { name: /go back/i });

      // Click multiple times
      await user.click(backButton);
      await user.click(backButton);

      expect(mockNavigate).toHaveBeenCalledTimes(2);
      expect(mockNavigate).toHaveBeenCalledWith(-1);
    });

    it('should maintain proper layout structure', () => {
      const { container } = render(<NotFound />, { wrapper: createWrapper() });

      // Check container structure
      const outerContainer = container.querySelector('.min-h-screen.flex.items-center.justify-center');
      expect(outerContainer).toBeInTheDocument();

      const innerContainer = outerContainer?.querySelector('.max-w-md.w-full.text-center');
      expect(innerContainer).toBeInTheDocument();
    });
  });

  describe('Error Edge Cases', () => {
    it('should render without crashing when navigation is unavailable', () => {
      render(<NotFound />, { wrapper: createWrapper() });

      expect(screen.getByText('Page Not Found')).toBeInTheDocument();
    });

    it('should handle rapid "Go Back" clicks gracefully', async () => {
      const user = userEvent.setup();
      render(<NotFound />, { wrapper: createWrapper() });

      const backButton = screen.getByRole('button', { name: /go back/i });

      // Rapid clicks
      await user.click(backButton);
      await user.click(backButton);
      await user.click(backButton);

      expect(mockNavigate).toHaveBeenCalledTimes(3);
    });

    it('should render all buttons even if navigate function fails', () => {
      mockNavigate.mockImplementation(() => {
        throw new Error('Navigation failed');
      });

      render(<NotFound />, { wrapper: createWrapper() });

      expect(screen.getByRole('link', { name: /go home/i })).toBeInTheDocument();
      expect(screen.getByRole('button', { name: /go back/i })).toBeInTheDocument();
    });
  });
});
