/**
 * Comprehensive unit tests for BusinessLayout component
 *
 * Tests all layout functionality including:
 * - Rendering children content via Outlet
 * - Sidebar navigation present (desktop and mobile)
 * - TopBar/header rendering
 * - Mobile responsive behavior
 * - User info displayed
 * - Masquerade banner display
 * - Trial banner display
 * - Sandbox banner display
 * - Quota warning/modal display
 * - Onboarding wizard display
 * - Ticket modal display
 * - Brand color application
 * - Trial expiration redirect
 */

import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { BrowserRouter, MemoryRouter } from 'react-router-dom';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import BusinessLayout from '../BusinessLayout';
import { Business, User } from '../../types';

// Mock all child components
vi.mock('../../components/Sidebar', () => ({
  default: ({ business, user, isCollapsed }: any) => (
    <div data-testid="sidebar">
      Sidebar - {business.name} - {user.name} - {isCollapsed ? 'Collapsed' : 'Expanded'}
    </div>
  ),
}));

vi.mock('../../components/TopBar', () => ({
  default: ({ user, isDarkMode, toggleTheme, onMenuClick }: any) => (
    <div data-testid="topbar">
      TopBar - {user.name} - {isDarkMode ? 'Dark' : 'Light'}
      <button onClick={toggleTheme} data-testid="theme-toggle">Toggle Theme</button>
      <button onClick={onMenuClick} data-testid="menu-button">Menu</button>
      <div data-testid="help-button">Help</div>
    </div>
  ),
}));

vi.mock('../../components/TrialBanner', () => ({
  default: ({ business }: any) => (
    <div data-testid="trial-banner">Trial Banner - {business.name}</div>
  ),
}));

vi.mock('../../components/SandboxBanner', () => ({
  default: ({ isSandbox, onSwitchToLive }: any) => (
    <div data-testid="sandbox-banner">
      Sandbox: {isSandbox ? 'Yes' : 'No'}
      <button onClick={() => onSwitchToLive()} data-testid="sandbox-toggle">Switch to Live</button>
    </div>
  ),
}));

vi.mock('../../components/QuotaWarningBanner', () => ({
  default: ({ overages }: any) => (
    <div data-testid="quota-warning-banner">Quota Warning - {overages.length} overages</div>
  ),
}));

vi.mock('../../components/QuotaOverageModal', () => ({
  default: ({ overages }: any) => (
    <div data-testid="quota-overage-modal">Quota Modal - {overages.length} overages</div>
  ),
  resetQuotaOverageModalDismissal: vi.fn(),
}));

vi.mock('../../components/MasqueradeBanner', () => ({
  default: ({ effectiveUser, originalUser, onStop }: any) => (
    <div data-testid="masquerade-banner">
      Masquerading as {effectiveUser.name} (Original: {originalUser.name})
      <button onClick={onStop} data-testid="stop-masquerade">Stop</button>
    </div>
  ),
}));

vi.mock('../../components/OnboardingWizard', () => ({
  default: ({ business, onComplete, onSkip }: any) => (
    <div data-testid="onboarding-wizard">
      Onboarding - {business.name}
      <button onClick={onComplete} data-testid="complete-onboarding">Complete</button>
      <button onClick={onSkip} data-testid="skip-onboarding">Skip</button>
    </div>
  ),
}));

vi.mock('../../components/TicketModal', () => ({
  default: ({ ticket, onClose }: any) => (
    <div data-testid="ticket-modal">
      Ticket #{ticket.id}
      <button onClick={onClose} data-testid="close-ticket">Close</button>
    </div>
  ),
}));

// HelpButton is now rendered inside TopBar, not as a separate component

// Mock hooks
vi.mock('../../hooks/useAuth', () => ({
  useStopMasquerade: vi.fn(() => ({
    mutate: vi.fn(),
  })),
}));

vi.mock('../../hooks/useNotificationWebSocket', () => ({
  useNotificationWebSocket: vi.fn(),
}));

vi.mock('../../hooks/useTickets', () => ({
  useTicket: vi.fn((id) => ({
    data: id ? { id, title: 'Test Ticket' } : null,
  })),
}));

vi.mock('../../hooks/useScrollToTop', () => ({
  useScrollToTop: vi.fn(),
}));

// Mock SandboxContext
const mockToggleSandbox = vi.fn();
vi.mock('../../contexts/SandboxContext', () => ({
  SandboxProvider: ({ children }: any) => <div>{children}</div>,
  useSandbox: () => ({
    isSandbox: false,
    sandboxEnabled: true,
    toggleSandbox: mockToggleSandbox,
    isToggling: false,
  }),
}));

// Mock color utilities
vi.mock('../../utils/colorUtils', () => ({
  applyBrandColors: vi.fn(),
  applyColorPalette: vi.fn(),
  defaultColorPalette: {},
}));

// Mock react-router-dom's Outlet
vi.mock('react-router-dom', async () => {
  const actual = await vi.importActual('react-router-dom');
  return {
    ...actual,
    Outlet: ({ context }: any) => (
      <div data-testid="outlet">
        Outlet Content - User: {context?.user?.name}
      </div>
    ),
  };
});

describe('BusinessLayout', () => {
  let queryClient: QueryClient;

  const mockBusiness: Business = {
    id: '1',
    name: 'Test Business',
    subdomain: 'test',
    primaryColor: '#2563eb',
    secondaryColor: '#0ea5e9',
    whitelabelEnabled: false,
    plan: 'Professional',
    status: 'Active',
    paymentsEnabled: true,
    requirePaymentMethodToBook: false,
    cancellationWindowHours: 24,
    lateCancellationFeePercent: 50,
    isTrialActive: false,
    isTrialExpired: false,
  };

  const mockUser: User = {
    id: '1',
    name: 'John Doe',
    email: 'john@test.com',
    role: 'owner',
  };

  const defaultProps = {
    business: mockBusiness,
    user: mockUser,
    darkMode: false,
    toggleTheme: vi.fn(),
    onSignOut: vi.fn(),
    updateBusiness: vi.fn(),
  };

  beforeEach(() => {
    queryClient = new QueryClient({
      defaultOptions: {
        queries: { retry: false },
        mutations: { retry: false },
      },
    });
    vi.clearAllMocks();
    localStorage.clear();
  });

  afterEach(() => {
    queryClient.clear();
  });

  const renderLayout = (props = {}, initialRoute = '/') => {
    return render(
      <QueryClientProvider client={queryClient}>
        <MemoryRouter initialEntries={[initialRoute]}>
          <BusinessLayout {...defaultProps} {...props} />
        </MemoryRouter>
      </QueryClientProvider>
    );
  };

  describe('Basic Rendering', () => {
    it('should render the layout with all main components', () => {
      renderLayout();

      expect(screen.getAllByTestId('sidebar').length).toBeGreaterThan(0);
      expect(screen.getByTestId('topbar')).toBeInTheDocument();
      expect(screen.getByTestId('outlet')).toBeInTheDocument();
      expect(screen.getByTestId('help-button')).toBeInTheDocument();
    });

    it('should render children content via Outlet', () => {
      renderLayout();

      const outlet = screen.getByTestId('outlet');
      expect(outlet).toBeInTheDocument();
      expect(outlet).toHaveTextContent('Outlet Content - User: John Doe');
    });

    it('should pass context to Outlet with user, business, and updateBusiness', () => {
      renderLayout();

      const outlet = screen.getByTestId('outlet');
      expect(outlet).toHaveTextContent('User: John Doe');
    });
  });

  describe('Sidebar Navigation', () => {
    it('should render sidebar with business and user info', () => {
      renderLayout();

      const sidebar = screen.getAllByTestId('sidebar')[0];
      expect(sidebar).toBeInTheDocument();
      expect(sidebar).toHaveTextContent('Test Business');
      expect(sidebar).toHaveTextContent('John Doe');
    });

    it('should render sidebar in expanded state by default on desktop', () => {
      renderLayout();

      const sidebar = screen.getAllByTestId('sidebar')[0];
      expect(sidebar).toHaveTextContent('Expanded');
    });

    it('should hide mobile menu by default', () => {
      renderLayout();

      // Mobile menu has translate-x-full class when closed
      const container = screen.getAllByTestId('sidebar')[0].closest('div');
      // The visible sidebar on desktop should exist
      expect(screen.getAllByTestId('sidebar').length).toBeGreaterThan(0);
    });

    it('should open mobile menu when menu button is clicked', () => {
      renderLayout();

      const menuButton = screen.getByTestId('menu-button');
      fireEvent.click(menuButton);

      // After clicking, mobile menu should be visible
      // Both mobile and desktop sidebars exist in DOM
      const sidebars = screen.getAllByTestId('sidebar');
      expect(sidebars.length).toBeGreaterThanOrEqual(1);
    });
  });

  describe('Header/TopBar', () => {
    it('should render TopBar with user info', () => {
      renderLayout();

      const topbar = screen.getByTestId('topbar');
      expect(topbar).toBeInTheDocument();
      expect(topbar).toHaveTextContent('John Doe');
    });

    it('should display dark mode state in TopBar', () => {
      renderLayout({ darkMode: true });

      const topbar = screen.getByTestId('topbar');
      expect(topbar).toHaveTextContent('Dark');
    });

    it('should display light mode state in TopBar', () => {
      renderLayout({ darkMode: false });

      const topbar = screen.getByTestId('topbar');
      expect(topbar).toHaveTextContent('Light');
    });

    it('should call toggleTheme when theme toggle is clicked', () => {
      const toggleTheme = vi.fn();
      renderLayout({ toggleTheme });

      const themeToggle = screen.getByTestId('theme-toggle');
      fireEvent.click(themeToggle);

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

  describe('Mobile Responsive Behavior', () => {
    it('should toggle mobile menu when menu button is clicked', () => {
      renderLayout();

      const menuButton = screen.getByTestId('menu-button');

      // Click to open
      fireEvent.click(menuButton);

      // Both mobile and desktop sidebars should exist
      expect(screen.getAllByTestId('sidebar').length).toBeGreaterThanOrEqual(1);
    });

    it('should render mobile and desktop sidebars separately', () => {
      renderLayout();

      // Desktop sidebar should be visible
      expect(screen.getAllByTestId('sidebar').length).toBeGreaterThan(0);
    });
  });

  describe('User Info Display', () => {
    it('should display user name in TopBar', () => {
      renderLayout();

      const topbar = screen.getByTestId('topbar');
      expect(topbar).toHaveTextContent('John Doe');
    });

    it('should display user name in Sidebar', () => {
      renderLayout();

      const sidebar = screen.getAllByTestId('sidebar')[0];
      expect(sidebar).toHaveTextContent('John Doe');
    });

    it('should display different user roles correctly', () => {
      const staffUser: User = {
        id: '2',
        name: 'Jane Smith',
        email: 'jane@test.com',
        role: 'staff',
      };

      renderLayout({ user: staffUser });

      expect(screen.getAllByTestId('sidebar')[0]).toHaveTextContent('Jane Smith');
      expect(screen.getByTestId('topbar')).toHaveTextContent('Jane Smith');
    });
  });

  describe('Masquerade Banner', () => {
    it('should not display masquerade banner when not masquerading', () => {
      renderLayout();

      expect(screen.queryByTestId('masquerade-banner')).not.toBeInTheDocument();
    });

    it('should display masquerade banner when masquerading', () => {
      // Simulate masquerade stack in localStorage
      const masqueradeStack = [
        {
          user_id: '999',
          username: 'admin',
          role: 'superuser',
        },
      ];
      localStorage.setItem('masquerade_stack', JSON.stringify(masqueradeStack));

      renderLayout();

      expect(screen.getByTestId('masquerade-banner')).toBeInTheDocument();
    });

    it('should call stop masquerade when stop button is clicked', async () => {
      const { useStopMasquerade } = await import('../../hooks/useAuth');
      const mockMutate = vi.fn();
      (useStopMasquerade as any).mockReturnValue({
        mutate: mockMutate,
      });

      const masqueradeStack = [
        {
          user_id: '999',
          username: 'admin',
          role: 'superuser',
        },
      ];
      localStorage.setItem('masquerade_stack', JSON.stringify(masqueradeStack));

      renderLayout();

      const stopButton = screen.getByTestId('stop-masquerade');
      fireEvent.click(stopButton);

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

  describe('Trial Banner', () => {
    it('should display trial banner when trial is active and payments not enabled', () => {
      const trialBusiness = {
        ...mockBusiness,
        isTrialActive: true,
        paymentsEnabled: false,
        plan: 'Professional',
      };

      renderLayout({ business: trialBusiness });

      expect(screen.getByTestId('trial-banner')).toBeInTheDocument();
    });

    it('should not display trial banner when trial is not active', () => {
      const activeBusiness = {
        ...mockBusiness,
        isTrialActive: false,
        paymentsEnabled: false,
      };

      renderLayout({ business: activeBusiness });

      expect(screen.queryByTestId('trial-banner')).not.toBeInTheDocument();
    });

    it('should not display trial banner when payments are enabled', () => {
      const paidBusiness = {
        ...mockBusiness,
        isTrialActive: true,
        paymentsEnabled: true,
      };

      renderLayout({ business: paidBusiness });

      expect(screen.queryByTestId('trial-banner')).not.toBeInTheDocument();
    });

    it('should not display trial banner for Free plan even if trial active', () => {
      const freeBusiness = {
        ...mockBusiness,
        isTrialActive: true,
        paymentsEnabled: false,
        plan: 'Free' as const,
      };

      renderLayout({ business: freeBusiness });

      expect(screen.queryByTestId('trial-banner')).not.toBeInTheDocument();
    });
  });

  describe('Sandbox Banner', () => {
    it('should display sandbox banner', () => {
      renderLayout();

      expect(screen.getByTestId('sandbox-banner')).toBeInTheDocument();
    });

    it('should call toggleSandbox when switch button is clicked', () => {
      renderLayout();

      const toggleButton = screen.getByTestId('sandbox-toggle');
      fireEvent.click(toggleButton);

      expect(mockToggleSandbox).toHaveBeenCalled();
    });
  });

  describe('Quota Warning and Modal', () => {
    it('should display quota warning banner when user has overages', () => {
      const userWithOverages: User = {
        ...mockUser,
        quota_overages: [
          {
            id: 1,
            quota_type: 'resources',
            display_name: 'Resources',
            current_usage: 15,
            allowed_limit: 10,
            overage_amount: 5,
            days_remaining: 7,
            grace_period_ends_at: '2025-12-14',
          },
        ],
      };

      renderLayout({ user: userWithOverages });

      expect(screen.getByTestId('quota-warning-banner')).toBeInTheDocument();
      expect(screen.getByTestId('quota-warning-banner')).toHaveTextContent('1 overages');
    });

    it('should display quota overage modal when user has overages', () => {
      const userWithOverages: User = {
        ...mockUser,
        quota_overages: [
          {
            id: 1,
            quota_type: 'resources',
            display_name: 'Resources',
            current_usage: 15,
            allowed_limit: 10,
            overage_amount: 5,
            days_remaining: 7,
            grace_period_ends_at: '2025-12-14',
          },
        ],
      };

      renderLayout({ user: userWithOverages });

      expect(screen.getByTestId('quota-overage-modal')).toBeInTheDocument();
      expect(screen.getByTestId('quota-overage-modal')).toHaveTextContent('1 overages');
    });

    it('should not display quota components when user has no overages', () => {
      renderLayout();

      expect(screen.queryByTestId('quota-warning-banner')).not.toBeInTheDocument();
      expect(screen.queryByTestId('quota-overage-modal')).not.toBeInTheDocument();
    });
  });

  describe('Onboarding Wizard', () => {
    it('should not display onboarding wizard by default', () => {
      renderLayout();

      expect(screen.queryByTestId('onboarding-wizard')).not.toBeInTheDocument();
    });

    it('should display onboarding wizard when returning from Stripe Connect', () => {
      renderLayout({}, '/?onboarding=true');

      expect(screen.getByTestId('onboarding-wizard')).toBeInTheDocument();
    });

    it('should call updateBusiness when onboarding is completed', () => {
      const updateBusiness = vi.fn();
      renderLayout({ updateBusiness }, '/?onboarding=true');

      const completeButton = screen.getByTestId('complete-onboarding');
      fireEvent.click(completeButton);

      expect(updateBusiness).toHaveBeenCalledWith({ initialSetupComplete: true });
    });

    it('should disable payments when onboarding is skipped', () => {
      const updateBusiness = vi.fn();
      renderLayout({ updateBusiness }, '/?onboarding=true');

      const skipButton = screen.getByTestId('skip-onboarding');
      fireEvent.click(skipButton);

      expect(updateBusiness).toHaveBeenCalledWith({ paymentsEnabled: false });
    });

    it('should hide onboarding wizard after completion', () => {
      renderLayout({}, '/?onboarding=true');

      expect(screen.getByTestId('onboarding-wizard')).toBeInTheDocument();

      const completeButton = screen.getByTestId('complete-onboarding');
      fireEvent.click(completeButton);

      expect(screen.queryByTestId('onboarding-wizard')).not.toBeInTheDocument();
    });
  });

  describe('Ticket Modal', () => {
    it('should not display ticket modal by default', () => {
      renderLayout();

      expect(screen.queryByTestId('ticket-modal')).not.toBeInTheDocument();
    });

    // Note: Ticket modal opening requires TopBar to call onTicketClick prop
    // This would require a more complex mock of TopBar component
  });

  describe('Brand Colors', () => {
    it('should apply brand colors on mount', async () => {
      const { applyBrandColors } = await import('../../utils/colorUtils');

      renderLayout();

      expect(applyBrandColors).toHaveBeenCalledWith('#2563eb', '#0ea5e9');
    });

    it('should apply default secondary color if not provided', async () => {
      const { applyBrandColors } = await import('../../utils/colorUtils');

      const businessWithoutSecondary = {
        ...mockBusiness,
        secondaryColor: undefined,
      };

      renderLayout({ business: businessWithoutSecondary });

      expect(applyBrandColors).toHaveBeenCalledWith('#2563eb', '#2563eb');
    });

    it('should reset colors on unmount', async () => {
      const { applyColorPalette, defaultColorPalette } = await import('../../utils/colorUtils');

      const { unmount } = renderLayout();
      unmount();

      expect(applyColorPalette).toHaveBeenCalledWith(defaultColorPalette);
    });
  });

  describe('Layout Structure', () => {
    it('should have flex layout structure', () => {
      const { container } = renderLayout();

      // Find the flex container that wraps sidebar and main content
      const flexContainer = container.querySelector('.flex.h-full');
      expect(flexContainer).toBeInTheDocument();
    });

    it('should have main content area with overflow-auto', () => {
      renderLayout();

      // The main element should exist
      const outlet = screen.getByTestId('outlet');
      const mainElement = outlet.closest('main');
      expect(mainElement).toBeInTheDocument();
      expect(mainElement).toHaveClass('flex-1', 'overflow-auto');
    });

    it('should render floating help button', () => {
      renderLayout();

      expect(screen.getByTestId('help-button')).toBeInTheDocument();
    });
  });

  describe('Edge Cases', () => {
    it('should handle user with minimal properties', () => {
      const minimalUser: User = {
        id: '1',
        name: 'Test User',
        email: 'test@example.com',
        role: 'customer',
      };

      renderLayout({ user: minimalUser });

      expect(screen.getAllByTestId('sidebar')[0]).toHaveTextContent('Test User');
      expect(screen.getByTestId('topbar')).toHaveTextContent('Test User');
    });

    it('should handle business with minimal properties', () => {
      const minimalBusiness: Business = {
        id: '1',
        name: 'Minimal Business',
        subdomain: 'minimal',
        primaryColor: '#000000',
        secondaryColor: '#ffffff',
        whitelabelEnabled: false,
        paymentsEnabled: false,
        requirePaymentMethodToBook: false,
        cancellationWindowHours: 0,
        lateCancellationFeePercent: 0,
      };

      renderLayout({ business: minimalBusiness });

      expect(screen.getAllByTestId('sidebar')[0]).toHaveTextContent('Minimal Business');
    });

    it('should handle invalid masquerade stack in localStorage', () => {
      localStorage.setItem('masquerade_stack', 'invalid-json');

      expect(() => renderLayout()).not.toThrow();
      expect(screen.queryByTestId('masquerade-banner')).not.toBeInTheDocument();
    });

    it('should handle multiple quota overages', () => {
      const userWithMultipleOverages: User = {
        ...mockUser,
        quota_overages: [
          {
            id: 1,
            quota_type: 'resources',
            display_name: 'Resources',
            current_usage: 15,
            allowed_limit: 10,
            overage_amount: 5,
            days_remaining: 7,
            grace_period_ends_at: '2025-12-14',
          },
          {
            id: 2,
            quota_type: 'customers',
            display_name: 'Customers',
            current_usage: 550,
            allowed_limit: 500,
            overage_amount: 50,
            days_remaining: 7,
            grace_period_ends_at: '2025-12-14',
          },
        ],
      };

      renderLayout({ user: userWithMultipleOverages });

      expect(screen.getByTestId('quota-warning-banner')).toHaveTextContent('2 overages');
      expect(screen.getByTestId('quota-overage-modal')).toHaveTextContent('2 overages');
    });
  });

  describe('Accessibility', () => {
    it('should have main content area with tabIndex for focus', () => {
      renderLayout();

      const outlet = screen.getByTestId('outlet');
      const mainElement = outlet.closest('main');
      expect(mainElement).toHaveAttribute('tabIndex', '-1');
    });

    it('should have focus:outline-none on main content', () => {
      renderLayout();

      const outlet = screen.getByTestId('outlet');
      const mainElement = outlet.closest('main');
      expect(mainElement).toHaveClass('focus:outline-none');
    });
  });

  describe('Component Integration', () => {
    it('should render all components together without crashing', () => {
      const userWithOverages: User = {
        ...mockUser,
        quota_overages: [
          {
            id: 1,
            quota_type: 'resources',
            display_name: 'Resources',
            current_usage: 15,
            allowed_limit: 10,
            overage_amount: 5,
            days_remaining: 7,
            grace_period_ends_at: '2025-12-14',
          },
        ],
      };

      const trialBusiness = {
        ...mockBusiness,
        isTrialActive: true,
        paymentsEnabled: false,
      };

      localStorage.setItem(
        'masquerade_stack',
        JSON.stringify([
          {
            user_id: '999',
            username: 'admin',
            role: 'superuser',
          },
        ])
      );

      expect(() =>
        renderLayout({ user: userWithOverages, business: trialBusiness }, '/?onboarding=true')
      ).not.toThrow();

      // All banners and components should be present
      expect(screen.getByTestId('masquerade-banner')).toBeInTheDocument();
      expect(screen.getByTestId('quota-warning-banner')).toBeInTheDocument();
      expect(screen.getByTestId('quota-overage-modal')).toBeInTheDocument();
      expect(screen.getByTestId('sandbox-banner')).toBeInTheDocument();
      expect(screen.getByTestId('trial-banner')).toBeInTheDocument();
      expect(screen.getByTestId('onboarding-wizard')).toBeInTheDocument();
      expect(screen.getAllByTestId('sidebar').length).toBeGreaterThan(0);
      expect(screen.getByTestId('topbar')).toBeInTheDocument();
      expect(screen.getByTestId('outlet')).toBeInTheDocument();
      expect(screen.getByTestId('help-button')).toBeInTheDocument();
    });
  });
});
