/**
 * Unit tests for MarketingLayout component
 *
 * Tests cover:
 * - Rendering children content via Outlet
 * - Contains Navbar component with correct props
 * - Contains Footer component
 * - Dark mode state management and localStorage integration
 * - Theme toggle functionality
 * - Document class toggling for dark mode
 * - Correct layout structure and styling
 * - Scroll-to-top behavior via useScrollToTop hook
 * - User prop passing to Navbar
 */

import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import userEvent from '@testing-library/user-event';
import React from 'react';
import MarketingLayout from '../MarketingLayout';
import { User } from '../../api/auth';

// Mock child components
vi.mock('../../components/marketing/Navbar', () => ({
  default: ({ darkMode, toggleTheme, user }: any) => (
    <div data-testid="navbar">
      <span data-testid="navbar-darkmode">{darkMode ? 'dark' : 'light'}</span>
      <button data-testid="navbar-toggle" onClick={toggleTheme}>
        Toggle Theme
      </button>
      {user && <span data-testid="navbar-user">{user.email}</span>}
    </div>
  ),
}));

vi.mock('../../components/marketing/Footer', () => ({
  default: () => <div data-testid="footer">Footer Content</div>,
}));

// Create the mock function inside the factory to avoid hoisting issues
vi.mock('../../hooks/useScrollToTop', () => ({
  useScrollToTop: vi.fn(),
}));

// Mock react-i18next
vi.mock('react-i18next', () => ({
  useTranslation: () => ({
    t: (key: string) => key,
  }),
}));

// Create a wrapper component with Router
const TestWrapper = ({ children, initialRoute = '/' }: { children: React.ReactNode; initialRoute?: string }) => {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={children}>
          <Route index element={<div data-testid="home-content">Home Page</div>} />
          <Route path="about" element={<div data-testid="about-content">About Page</div>} />
        </Route>
      </Routes>
    </BrowserRouter>
  );
};

describe('MarketingLayout', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    // Clear localStorage before each test
    localStorage.clear();
    // Clear document.documentElement classes
    document.documentElement.classList.remove('dark');
  });

  afterEach(() => {
    vi.clearAllMocks();
  });

  describe('Component Rendering', () => {
    it('should render the layout', () => {
      render(
        <TestWrapper>
          <MarketingLayout />
        </TestWrapper>
      );

      expect(screen.getByTestId('navbar')).toBeInTheDocument();
      expect(screen.getByTestId('footer')).toBeInTheDocument();
    });

    it('should render children content via Outlet', () => {
      render(
        <TestWrapper>
          <MarketingLayout />
        </TestWrapper>
      );

      expect(screen.getByTestId('home-content')).toBeInTheDocument();
      expect(screen.getByText('Home Page')).toBeInTheDocument();
    });

    it('should render all major layout sections', () => {
      const { container } = render(
        <TestWrapper>
          <MarketingLayout />
        </TestWrapper>
      );

      // Check for main container
      const mainElement = container.querySelector('main');
      expect(mainElement).toBeInTheDocument();

      // Check for navbar, main, and footer
      expect(screen.getByTestId('navbar')).toBeInTheDocument();
      expect(mainElement).toBeInTheDocument();
      expect(screen.getByTestId('footer')).toBeInTheDocument();
    });
  });

  describe('Navbar Component', () => {
    it('should render Navbar component', () => {
      render(
        <TestWrapper>
          <MarketingLayout />
        </TestWrapper>
      );

      expect(screen.getByTestId('navbar')).toBeInTheDocument();
    });

    it('should pass darkMode prop to Navbar', () => {
      render(
        <TestWrapper>
          <MarketingLayout />
        </TestWrapper>
      );

      const darkModeIndicator = screen.getByTestId('navbar-darkmode');
      expect(darkModeIndicator).toBeInTheDocument();
    });

    it('should pass toggleTheme function to Navbar', () => {
      render(
        <TestWrapper>
          <MarketingLayout />
        </TestWrapper>
      );

      const toggleButton = screen.getByTestId('navbar-toggle');
      expect(toggleButton).toBeInTheDocument();
    });

    it('should pass user prop to Navbar when provided', () => {
      const mockUser: User = {
        id: 1,
        email: 'test@example.com',
        username: 'testuser',
        first_name: 'Test',
        last_name: 'User',
        role: 'owner',
        business_id: 1,
        business_name: 'Test Business',
        business_subdomain: 'test',
        business_logo: null,
        timezone: 'UTC',
        language: 'en',
        onboarding_completed: true,
      };

      render(
        <TestWrapper>
          <MarketingLayout user={mockUser} />
        </TestWrapper>
      );

      expect(screen.getByTestId('navbar-user')).toHaveTextContent('test@example.com');
    });

    it('should not render user info in Navbar when user is null', () => {
      render(
        <TestWrapper>
          <MarketingLayout user={null} />
        </TestWrapper>
      );

      expect(screen.queryByTestId('navbar-user')).not.toBeInTheDocument();
    });

    it('should not render user info in Navbar when user is undefined', () => {
      render(
        <TestWrapper>
          <MarketingLayout />
        </TestWrapper>
      );

      expect(screen.queryByTestId('navbar-user')).not.toBeInTheDocument();
    });
  });

  describe('Footer Component', () => {
    it('should render Footer component', () => {
      render(
        <TestWrapper>
          <MarketingLayout />
        </TestWrapper>
      );

      expect(screen.getByTestId('footer')).toBeInTheDocument();
    });

    it('should render Footer content', () => {
      render(
        <TestWrapper>
          <MarketingLayout />
        </TestWrapper>
      );

      expect(screen.getByText('Footer Content')).toBeInTheDocument();
    });
  });

  describe('Layout Styling and Structure', () => {
    it('should apply correct base classes to root container', () => {
      const { container } = render(
        <TestWrapper>
          <MarketingLayout />
        </TestWrapper>
      );

      const rootDiv = container.querySelector('.min-h-screen');
      expect(rootDiv).toBeInTheDocument();
      expect(rootDiv).toHaveClass('min-h-screen');
      expect(rootDiv).toHaveClass('flex');
      expect(rootDiv).toHaveClass('flex-col');
      expect(rootDiv).toHaveClass('bg-white');
      expect(rootDiv).toHaveClass('dark:bg-gray-900');
      expect(rootDiv).toHaveClass('transition-colors');
      expect(rootDiv).toHaveClass('duration-200');
    });

    it('should apply correct classes to main element', () => {
      const { container } = render(
        <TestWrapper>
          <MarketingLayout />
        </TestWrapper>
      );

      const mainElement = container.querySelector('main');
      expect(mainElement).toHaveClass('flex-1');
      expect(mainElement).toHaveClass('pt-16');
      expect(mainElement).toHaveClass('lg:pt-20');
    });

    it('should maintain flexbox layout structure', () => {
      const { container } = render(
        <TestWrapper>
          <MarketingLayout />
        </TestWrapper>
      );

      const rootDiv = container.querySelector('.flex.flex-col');
      expect(rootDiv).toBeInTheDocument();

      // Verify main has flex-1 for proper spacing
      const mainElement = rootDiv?.querySelector('main.flex-1');
      expect(mainElement).toBeInTheDocument();
    });
  });

  describe('Dark Mode State Management', () => {
    it('should initialize dark mode from localStorage if available', () => {
      localStorage.setItem('darkMode', JSON.stringify(true));

      render(
        <TestWrapper>
          <MarketingLayout />
        </TestWrapper>
      );

      expect(screen.getByTestId('navbar-darkmode')).toHaveTextContent('dark');
      expect(document.documentElement.classList.contains('dark')).toBe(true);
    });

    it('should initialize dark mode to false when not in localStorage', () => {
      // matchMedia is mocked to return false in setup.ts
      render(
        <TestWrapper>
          <MarketingLayout />
        </TestWrapper>
      );

      expect(screen.getByTestId('navbar-darkmode')).toHaveTextContent('light');
    });

    it('should respect system preference when no localStorage value exists', () => {
      // Override matchMedia to return true for dark mode preference
      window.matchMedia = vi.fn().mockImplementation((query) => ({
        matches: query === '(prefers-color-scheme: dark)',
        media: query,
        onchange: null,
        addListener: vi.fn(),
        removeListener: vi.fn(),
        addEventListener: vi.fn(),
        removeEventListener: vi.fn(),
        dispatchEvent: vi.fn(),
      }));

      render(
        <TestWrapper>
          <MarketingLayout />
        </TestWrapper>
      );

      expect(screen.getByTestId('navbar-darkmode')).toHaveTextContent('dark');
    });

    it('should save dark mode preference to localStorage on mount', () => {
      render(
        <TestWrapper>
          <MarketingLayout />
        </TestWrapper>
      );

      // The component should save the initial dark mode state to localStorage
      const savedValue = localStorage.getItem('darkMode');
      expect(savedValue).toBeDefined();
      expect(['true', 'false']).toContain(savedValue);
    });

    it('should update localStorage when dark mode is toggled', async () => {
      const user = userEvent.setup();

      render(
        <TestWrapper>
          <MarketingLayout />
        </TestWrapper>
      );

      // Get initial state
      const initialDarkMode = screen.getByTestId('navbar-darkmode').textContent;
      const expectedAfterToggle = initialDarkMode === 'light' ? 'true' : 'false';

      const toggleButton = screen.getByTestId('navbar-toggle');
      await user.click(toggleButton);

      await waitFor(() => {
        const savedValue = localStorage.getItem('darkMode');
        expect(savedValue).toBe(expectedAfterToggle);
      });
    });
  });

  describe('Theme Toggle Functionality', () => {
    it('should toggle dark mode when toggle button is clicked', async () => {
      const user = userEvent.setup();

      render(
        <TestWrapper>
          <MarketingLayout />
        </TestWrapper>
      );

      const darkModeIndicator = screen.getByTestId('navbar-darkmode');
      const initialState = darkModeIndicator.textContent;

      const toggleButton = screen.getByTestId('navbar-toggle');
      await user.click(toggleButton);

      await waitFor(() => {
        const newState = screen.getByTestId('navbar-darkmode').textContent;
        expect(newState).not.toBe(initialState);
        expect(['light', 'dark']).toContain(newState);
      });
    });

    it('should toggle back to light mode when clicked again', async () => {
      const user = userEvent.setup();

      render(
        <TestWrapper>
          <MarketingLayout />
        </TestWrapper>
      );

      const toggleButton = screen.getByTestId('navbar-toggle');
      const initialState = screen.getByTestId('navbar-darkmode').textContent;

      // First toggle
      await user.click(toggleButton);
      await waitFor(() => {
        const firstToggleState = screen.getByTestId('navbar-darkmode').textContent;
        expect(firstToggleState).not.toBe(initialState);
      });

      const afterFirstToggle = screen.getByTestId('navbar-darkmode').textContent;

      // Second toggle - should go back to initial state
      await user.click(toggleButton);
      await waitFor(() => {
        const secondToggleState = screen.getByTestId('navbar-darkmode').textContent;
        expect(secondToggleState).toBe(initialState);
        expect(secondToggleState).not.toBe(afterFirstToggle);
      });
    });

    it('should add dark class to document when dark mode is enabled', async () => {
      const user = userEvent.setup();

      // Start with light mode explicitly
      localStorage.setItem('darkMode', 'false');
      document.documentElement.classList.remove('dark');

      render(
        <TestWrapper>
          <MarketingLayout />
        </TestWrapper>
      );

      const toggleButton = screen.getByTestId('navbar-toggle');
      await user.click(toggleButton);

      await waitFor(() => {
        expect(document.documentElement.classList.contains('dark')).toBe(true);
      });
    });

    it('should remove dark class from document when dark mode is disabled', async () => {
      const user = userEvent.setup();

      // Start with dark mode enabled
      localStorage.setItem('darkMode', JSON.stringify(true));

      render(
        <TestWrapper>
          <MarketingLayout />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(document.documentElement.classList.contains('dark')).toBe(true);
      });

      const toggleButton = screen.getByTestId('navbar-toggle');
      await user.click(toggleButton);

      await waitFor(() => {
        expect(document.documentElement.classList.contains('dark')).toBe(false);
      });
    });

    it('should persist dark mode state across multiple toggles', async () => {
      const user = userEvent.setup();

      // Start with explicit light mode
      localStorage.setItem('darkMode', 'false');

      render(
        <TestWrapper>
          <MarketingLayout />
        </TestWrapper>
      );

      const toggleButton = screen.getByTestId('navbar-toggle');
      const initialValue = localStorage.getItem('darkMode');

      // Toggle on
      await user.click(toggleButton);
      await waitFor(() => {
        const newValue = localStorage.getItem('darkMode');
        expect(newValue).not.toBe(initialValue);
      });

      const afterFirstToggle = localStorage.getItem('darkMode');

      // Toggle off
      await user.click(toggleButton);
      await waitFor(() => {
        const newValue = localStorage.getItem('darkMode');
        expect(newValue).toBe(initialValue);
        expect(newValue).not.toBe(afterFirstToggle);
      });

      // Toggle on again
      await user.click(toggleButton);
      await waitFor(() => {
        const newValue = localStorage.getItem('darkMode');
        expect(newValue).toBe(afterFirstToggle);
        expect(newValue).not.toBe(initialValue);
      });
    });
  });

  describe('Document Class Management', () => {
    it('should apply dark class to document.documentElement when dark mode is true', async () => {
      localStorage.setItem('darkMode', JSON.stringify(true));

      render(
        <TestWrapper>
          <MarketingLayout />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(document.documentElement.classList.contains('dark')).toBe(true);
      });
    });

    it('should not apply dark class when dark mode is false', async () => {
      localStorage.setItem('darkMode', JSON.stringify(false));

      render(
        <TestWrapper>
          <MarketingLayout />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(document.documentElement.classList.contains('dark')).toBe(false);
      });
    });

    it('should update document class when dark mode changes', async () => {
      const user = userEvent.setup();

      // Start with explicit light mode
      localStorage.setItem('darkMode', 'false');
      document.documentElement.classList.remove('dark');

      render(
        <TestWrapper>
          <MarketingLayout />
        </TestWrapper>
      );

      // Initially light mode
      expect(document.documentElement.classList.contains('dark')).toBe(false);

      // Toggle to dark mode
      const toggleButton = screen.getByTestId('navbar-toggle');
      await user.click(toggleButton);

      await waitFor(() => {
        expect(document.documentElement.classList.contains('dark')).toBe(true);
      });

      // Toggle back to light mode
      await user.click(toggleButton);

      await waitFor(() => {
        expect(document.documentElement.classList.contains('dark')).toBe(false);
      });
    });
  });

  describe('Scroll Behavior', () => {
    it('should call useScrollToTop hook', async () => {
      // Import the mocked module to access the mock
      const { useScrollToTop } = await import('../../hooks/useScrollToTop');

      render(
        <TestWrapper>
          <MarketingLayout />
        </TestWrapper>
      );

      expect(useScrollToTop).toHaveBeenCalled();
    });
  });

  describe('Integration Tests', () => {
    it('should render complete layout with all components and props', async () => {
      const mockUser: User = {
        id: 1,
        email: 'integration@example.com',
        username: 'integrationuser',
        first_name: 'Integration',
        last_name: 'Test',
        role: 'manager',
        business_id: 1,
        business_name: 'Integration Business',
        business_subdomain: 'integration',
        business_logo: null,
        timezone: 'America/New_York',
        language: 'en',
        onboarding_completed: true,
      };

      const { container } = render(
        <TestWrapper>
          <MarketingLayout user={mockUser} />
        </TestWrapper>
      );

      // Verify all major components
      expect(screen.getByTestId('navbar')).toBeInTheDocument();
      expect(screen.getByTestId('footer')).toBeInTheDocument();
      expect(screen.getByTestId('home-content')).toBeInTheDocument();

      // Verify user is passed to navbar
      expect(screen.getByTestId('navbar-user')).toHaveTextContent('integration@example.com');

      // Verify main element exists and has proper styling
      const mainElement = container.querySelector('main');
      expect(mainElement).toBeInTheDocument();
      expect(mainElement).toHaveClass('flex-1', 'pt-16', 'lg:pt-20');

      // Verify root container styling
      const rootDiv = container.querySelector('.min-h-screen');
      expect(rootDiv).toHaveClass('flex', 'flex-col', 'bg-white', 'dark:bg-gray-900');
    });

    it('should maintain layout structure when switching routes', async () => {
      const { container } = render(
        <BrowserRouter>
          <Routes>
            <Route path="/" element={<MarketingLayout />}>
              <Route index element={<div data-testid="home-content">Home</div>} />
              <Route path="about" element={<div data-testid="about-content">About</div>} />
            </Route>
          </Routes>
        </BrowserRouter>
      );

      // Verify home content is rendered
      expect(screen.getByTestId('home-content')).toBeInTheDocument();

      // Navbar and Footer should persist
      expect(screen.getByTestId('navbar')).toBeInTheDocument();
      expect(screen.getByTestId('footer')).toBeInTheDocument();

      // Main element structure should remain
      const mainElement = container.querySelector('main');
      expect(mainElement).toBeInTheDocument();
    });

    it('should handle dark mode toggle with user prop', async () => {
      const user = userEvent.setup();
      const mockUser: User = {
        id: 1,
        email: 'darkmode@example.com',
        username: 'darkmodeuser',
        first_name: 'Dark',
        last_name: 'Mode',
        role: 'owner',
        business_id: 1,
        business_name: 'Dark Mode Business',
        business_subdomain: 'darkmode',
        business_logo: null,
        timezone: 'UTC',
        language: 'en',
        onboarding_completed: true,
      };

      // Start with light mode
      localStorage.setItem('darkMode', 'false');
      document.documentElement.classList.remove('dark');

      render(
        <TestWrapper>
          <MarketingLayout user={mockUser} />
        </TestWrapper>
      );

      const toggleButton = screen.getByTestId('navbar-toggle');
      const initialDarkModeState = screen.getByTestId('navbar-darkmode').textContent;

      // Verify user is displayed
      expect(screen.getByTestId('navbar-user')).toHaveTextContent('darkmode@example.com');

      // Toggle dark mode
      await user.click(toggleButton);

      await waitFor(() => {
        const newDarkModeState = screen.getByTestId('navbar-darkmode').textContent;
        expect(newDarkModeState).not.toBe(initialDarkModeState);
        expect(screen.getByTestId('navbar-user')).toHaveTextContent('darkmode@example.com');
      });
    });
  });

  describe('Edge Cases', () => {
    it('should handle SSR environment gracefully (window undefined)', () => {
      // This test verifies the typeof window !== 'undefined' check
      // In jsdom, window is always defined, but the code should handle its absence
      render(
        <TestWrapper>
          <MarketingLayout />
        </TestWrapper>
      );

      expect(screen.getByTestId('navbar')).toBeInTheDocument();
    });

    it('should handle missing localStorage gracefully', async () => {
      // Temporarily break localStorage
      const originalSetItem = localStorage.setItem;
      localStorage.setItem = vi.fn(() => {
        throw new Error('localStorage error');
      });

      // Should not crash
      const { container } = render(
        <TestWrapper>
          <MarketingLayout />
        </TestWrapper>
      );

      expect(container).toBeInTheDocument();

      // Restore localStorage
      localStorage.setItem = originalSetItem;
    });

    it('should handle undefined user prop gracefully', () => {
      render(
        <TestWrapper>
          <MarketingLayout user={undefined} />
        </TestWrapper>
      );

      expect(screen.getByTestId('navbar')).toBeInTheDocument();
      expect(screen.queryByTestId('navbar-user')).not.toBeInTheDocument();
    });

    it('should handle null user prop gracefully', () => {
      render(
        <TestWrapper>
          <MarketingLayout user={null} />
        </TestWrapper>
      );

      expect(screen.getByTestId('navbar')).toBeInTheDocument();
      expect(screen.queryByTestId('navbar-user')).not.toBeInTheDocument();
    });
  });
});
