/**
 * Unit tests for PublicSiteLayout component
 *
 * Tests cover:
 * - Rendering children content
 * - Layout structure (header, main, footer)
 * - Business branding application (primary color, logo, name)
 * - Navigation links (website pages, customer login)
 * - Footer copyright information
 * - Scroll restoration via useScrollToTop hook
 */

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';
import React from 'react';
import PublicSiteLayout from '../PublicSiteLayout';
import { Business } from '../../types';

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

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

// Mock business data factory
const createMockBusiness = (overrides?: Partial<Business>): Business => ({
  id: 'biz-1',
  name: 'Test Business',
  subdomain: 'testbiz',
  primaryColor: '#3B82F6',
  secondaryColor: '#10B981',
  logoUrl: undefined,
  whitelabelEnabled: false,
  paymentsEnabled: false,
  requirePaymentMethodToBook: false,
  cancellationWindowHours: 24,
  lateCancellationFeePercent: 50,
  ...overrides,
});

describe('PublicSiteLayout', () => {
  let mockBusiness: Business;

  beforeEach(() => {
    vi.clearAllMocks();
    mockBusiness = createMockBusiness();
  });

  describe('Rendering', () => {
    it('should render the layout component', () => {
      const { container } = render(
        <PublicSiteLayout business={mockBusiness}>
          <div>Test Content</div>
        </PublicSiteLayout>,
        { wrapper: createWrapper() }
      );

      expect(container.firstChild).toBeInTheDocument();
    });

    it('should render children content', () => {
      render(
        <PublicSiteLayout business={mockBusiness}>
          <div>Child Content</div>
        </PublicSiteLayout>,
        { wrapper: createWrapper() }
      );

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

    it('should render multiple children', () => {
      render(
        <PublicSiteLayout business={mockBusiness}>
          <div>First Child</div>
          <div>Second Child</div>
          <div>Third Child</div>
        </PublicSiteLayout>,
        { wrapper: createWrapper() }
      );

      expect(screen.getByText('First Child')).toBeInTheDocument();
      expect(screen.getByText('Second Child')).toBeInTheDocument();
      expect(screen.getByText('Third Child')).toBeInTheDocument();
    });
  });

  describe('Layout Structure', () => {
    it('should have header, main, and footer sections', () => {
      const { container } = render(
        <PublicSiteLayout business={mockBusiness}>
          <div>Content</div>
        </PublicSiteLayout>,
        { wrapper: createWrapper() }
      );

      const header = container.querySelector('header');
      const main = container.querySelector('main');
      const footer = container.querySelector('footer');

      expect(header).toBeInTheDocument();
      expect(main).toBeInTheDocument();
      expect(footer).toBeInTheDocument();
    });

    it('should apply min-h-screen to container', () => {
      const { container } = render(
        <PublicSiteLayout business={mockBusiness}>
          <div>Content</div>
        </PublicSiteLayout>,
        { wrapper: createWrapper() }
      );

      const rootDiv = container.firstChild as HTMLElement;
      expect(rootDiv).toHaveClass('min-h-screen');
    });

    it('should apply background color classes', () => {
      const { container } = render(
        <PublicSiteLayout business={mockBusiness}>
          <div>Content</div>
        </PublicSiteLayout>,
        { wrapper: createWrapper() }
      );

      const rootDiv = container.firstChild as HTMLElement;
      expect(rootDiv).toHaveClass('bg-gray-50');
      expect(rootDiv).toHaveClass('dark:bg-gray-900');
    });

    it('should apply text color classes', () => {
      const { container } = render(
        <PublicSiteLayout business={mockBusiness}>
          <div>Content</div>
        </PublicSiteLayout>,
        { wrapper: createWrapper() }
      );

      const rootDiv = container.firstChild as HTMLElement;
      expect(rootDiv).toHaveClass('text-gray-900');
      expect(rootDiv).toHaveClass('dark:text-white');
    });

    it('should render main content in a container with padding', () => {
      const { container } = render(
        <PublicSiteLayout business={mockBusiness}>
          <div>Content</div>
        </PublicSiteLayout>,
        { wrapper: createWrapper() }
      );

      const main = container.querySelector('main');
      expect(main).toHaveClass('container');
      expect(main).toHaveClass('mx-auto');
      expect(main).toHaveClass('px-4');
      expect(main).toHaveClass('py-12');
    });
  });

  describe('Business Branding', () => {
    describe('Header Styling', () => {
      it('should apply business primary color to header background', () => {
        const business = createMockBusiness({ primaryColor: '#FF5733' });
        const { container } = render(
          <PublicSiteLayout business={business}>
            <div>Content</div>
          </PublicSiteLayout>,
          { wrapper: createWrapper() }
        );

        const header = container.querySelector('header');
        expect(header).toHaveStyle({ backgroundColor: '#FF5733' });
      });

      it('should apply shadow to header', () => {
        const { container } = render(
          <PublicSiteLayout business={mockBusiness}>
            <div>Content</div>
          </PublicSiteLayout>,
          { wrapper: createWrapper() }
        );

        const header = container.querySelector('header');
        expect(header).toHaveClass('shadow-md');
      });
    });

    describe('Business Logo/Name Display', () => {
      it('should display business name', () => {
        const business = createMockBusiness({ name: 'Acme Corp' });
        render(
          <PublicSiteLayout business={business}>
            <div>Content</div>
          </PublicSiteLayout>,
          { wrapper: createWrapper() }
        );

        expect(screen.getByText('Acme Corp')).toBeInTheDocument();
      });

      it('should display business name initials in logo placeholder', () => {
        const business = createMockBusiness({ name: 'Test Business' });
        render(
          <PublicSiteLayout business={business}>
            <div>Content</div>
          </PublicSiteLayout>,
          { wrapper: createWrapper() }
        );

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

      it('should capitalize initials', () => {
        const business = createMockBusiness({ name: 'acme corp' });
        render(
          <PublicSiteLayout business={business}>
            <div>Content</div>
          </PublicSiteLayout>,
          { wrapper: createWrapper() }
        );

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

      it('should apply primary color to logo placeholder text', () => {
        const business = createMockBusiness({
          name: 'Test Business',
          primaryColor: '#FF0000',
        });
        const { container } = render(
          <PublicSiteLayout business={business}>
            <div>Content</div>
          </PublicSiteLayout>,
          { wrapper: createWrapper() }
        );

        // The text "TE" is inside a div, not its parent
        const logoPlaceholder = screen.getByText('TE');
        expect(logoPlaceholder).toHaveStyle({ color: 'rgb(255, 0, 0)' });
      });

      it('should have white background for logo placeholder', () => {
        render(
          <PublicSiteLayout business={mockBusiness}>
            <div>Content</div>
          </PublicSiteLayout>,
          { wrapper: createWrapper() }
        );

        // The text "TE" is inside the div that has bg-white
        const logoPlaceholder = screen.getByText('TE');
        expect(logoPlaceholder).toHaveClass('bg-white');
      });

      it('should style business name in header', () => {
        render(
          <PublicSiteLayout business={mockBusiness}>
            <div>Content</div>
          </PublicSiteLayout>,
          { wrapper: createWrapper() }
        );

        const businessName = screen.getByText('Test Business');
        expect(businessName).toHaveClass('font-bold');
        expect(businessName).toHaveClass('text-xl');
        expect(businessName).toHaveClass('text-white');
      });
    });

    describe('Different Primary Colors', () => {
      it('should work with hex color', () => {
        const business = createMockBusiness({ primaryColor: '#3B82F6' });
        const { container } = render(
          <PublicSiteLayout business={business}>
            <div>Content</div>
          </PublicSiteLayout>,
          { wrapper: createWrapper() }
        );

        const header = container.querySelector('header');
        expect(header).toHaveStyle({ backgroundColor: '#3B82F6' });
      });

      it('should work with rgb color', () => {
        const business = createMockBusiness({ primaryColor: 'rgb(59, 130, 246)' });
        const { container } = render(
          <PublicSiteLayout business={business}>
            <div>Content</div>
          </PublicSiteLayout>,
          { wrapper: createWrapper() }
        );

        const header = container.querySelector('header');
        expect(header).toHaveStyle({ backgroundColor: 'rgb(59, 130, 246)' });
      });

      it('should work with named color', () => {
        const business = createMockBusiness({ primaryColor: 'blue' });
        const { container } = render(
          <PublicSiteLayout business={business}>
            <div>Content</div>
          </PublicSiteLayout>,
          { wrapper: createWrapper() }
        );

        const header = container.querySelector('header');
        // Browsers may convert 'blue' to rgb format
        const style = header?.getAttribute('style');
        expect(style).toContain('blue');
      });
    });
  });

  describe('Navigation', () => {
    describe('Website Pages Navigation', () => {
      it('should render website page links when websitePages exist', () => {
        const business = createMockBusiness({
          websitePages: {
            '/about': { name: 'About', content: [] },
            '/services': { name: 'Services', content: [] },
            '/contact': { name: 'Contact', content: [] },
          },
        });

        render(
          <PublicSiteLayout business={business}>
            <div>Content</div>
          </PublicSiteLayout>,
          { wrapper: createWrapper() }
        );

        expect(screen.getByRole('link', { name: 'About' })).toBeInTheDocument();
        expect(screen.getByRole('link', { name: 'Services' })).toBeInTheDocument();
        expect(screen.getByRole('link', { name: 'Contact' })).toBeInTheDocument();
      });

      it('should link to correct paths', () => {
        const business = createMockBusiness({
          websitePages: {
            '/about': { name: 'About', content: [] },
            '/services': { name: 'Services', content: [] },
          },
        });

        render(
          <PublicSiteLayout business={business}>
            <div>Content</div>
          </PublicSiteLayout>,
          { wrapper: createWrapper() }
        );

        const aboutLink = screen.getByRole('link', { name: 'About' });
        const servicesLink = screen.getByRole('link', { name: 'Services' });

        expect(aboutLink).toHaveAttribute('href', '/about');
        expect(servicesLink).toHaveAttribute('href', '/services');
      });

      it('should not render page links when websitePages is undefined', () => {
        const business = createMockBusiness({
          websitePages: undefined,
        });

        render(
          <PublicSiteLayout business={business}>
            <div>Content</div>
          </PublicSiteLayout>,
          { wrapper: createWrapper() }
        );

        // Only customer login link should exist
        const links = screen.getAllByRole('link');
        expect(links).toHaveLength(1);
        expect(links[0]).toHaveTextContent('Customer Login');
      });

      it('should not render page links when websitePages is empty', () => {
        const business = createMockBusiness({
          websitePages: {},
        });

        render(
          <PublicSiteLayout business={business}>
            <div>Content</div>
          </PublicSiteLayout>,
          { wrapper: createWrapper() }
        );

        // Only customer login link should exist
        const links = screen.getAllByRole('link');
        expect(links).toHaveLength(1);
      });

      it('should style navigation links with white text', () => {
        const business = createMockBusiness({
          websitePages: {
            '/about': { name: 'About', content: [] },
          },
        });

        render(
          <PublicSiteLayout business={business}>
            <div>Content</div>
          </PublicSiteLayout>,
          { wrapper: createWrapper() }
        );

        const aboutLink = screen.getByRole('link', { name: 'About' });
        expect(aboutLink).toHaveClass('text-white/80');
        expect(aboutLink).toHaveClass('hover:text-white');
      });
    });

    describe('Customer Login Link', () => {
      it('should render customer login link', () => {
        render(
          <PublicSiteLayout business={mockBusiness}>
            <div>Content</div>
          </PublicSiteLayout>,
          { wrapper: createWrapper() }
        );

        const loginLink = screen.getByRole('link', { name: /customer login/i });
        expect(loginLink).toBeInTheDocument();
      });

      it('should link to portal dashboard', () => {
        render(
          <PublicSiteLayout business={mockBusiness}>
            <div>Content</div>
          </PublicSiteLayout>,
          { wrapper: createWrapper() }
        );

        const loginLink = screen.getByRole('link', { name: /customer login/i });
        expect(loginLink).toHaveAttribute('href', '/portal/dashboard');
      });

      it('should style customer login as a button', () => {
        render(
          <PublicSiteLayout business={mockBusiness}>
            <div>Content</div>
          </PublicSiteLayout>,
          { wrapper: createWrapper() }
        );

        const loginLink = screen.getByRole('link', { name: /customer login/i });
        expect(loginLink).toHaveClass('px-4');
        expect(loginLink).toHaveClass('py-2');
        expect(loginLink).toHaveClass('bg-white/20');
        expect(loginLink).toHaveClass('text-white');
        expect(loginLink).toHaveClass('rounded-lg');
        expect(loginLink).toHaveClass('hover:bg-white/30');
      });

      it('should render login link even without website pages', () => {
        const business = createMockBusiness({
          websitePages: undefined,
        });

        render(
          <PublicSiteLayout business={business}>
            <div>Content</div>
          </PublicSiteLayout>,
          { wrapper: createWrapper() }
        );

        const loginLink = screen.getByRole('link', { name: /customer login/i });
        expect(loginLink).toBeInTheDocument();
      });
    });

    describe('Navigation Container', () => {
      it('should render navigation in a flex container', () => {
        const { container } = render(
          <PublicSiteLayout business={mockBusiness}>
            <div>Content</div>
          </PublicSiteLayout>,
          { wrapper: createWrapper() }
        );

        const nav = container.querySelector('nav');
        expect(nav).toHaveClass('flex');
        expect(nav).toHaveClass('items-center');
        expect(nav).toHaveClass('gap-4');
      });
    });
  });

  describe('Footer', () => {
    it('should render footer element', () => {
      const { container } = render(
        <PublicSiteLayout business={mockBusiness}>
          <div>Content</div>
        </PublicSiteLayout>,
        { wrapper: createWrapper() }
      );

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

    it('should display copyright with current year', () => {
      const currentYear = new Date().getFullYear();
      render(
        <PublicSiteLayout business={mockBusiness}>
          <div>Content</div>
        </PublicSiteLayout>,
        { wrapper: createWrapper() }
      );

      expect(screen.getByText(new RegExp(currentYear.toString()))).toBeInTheDocument();
    });

    it('should display business name in copyright', () => {
      const business = createMockBusiness({ name: 'Acme Corp' });
      render(
        <PublicSiteLayout business={business}>
          <div>Content</div>
        </PublicSiteLayout>,
        { wrapper: createWrapper() }
      );

      // Business name appears in both header and footer, use getAllByText
      const matches = screen.getAllByText(/Acme Corp/);
      expect(matches.length).toBeGreaterThan(0);
      // Check specifically in the footer by looking for copyright text
      expect(screen.getByText(/© .* Acme Corp. All Rights Reserved./)).toBeInTheDocument();
    });

    it('should display full copyright text', () => {
      const business = createMockBusiness({ name: 'Test Business' });
      const currentYear = new Date().getFullYear();
      render(
        <PublicSiteLayout business={business}>
          <div>Content</div>
        </PublicSiteLayout>,
        { wrapper: createWrapper() }
      );

      expect(
        screen.getByText(`© ${currentYear} Test Business. All Rights Reserved.`)
      ).toBeInTheDocument();
    });

    it('should style footer with background colors', () => {
      const { container } = render(
        <PublicSiteLayout business={mockBusiness}>
          <div>Content</div>
        </PublicSiteLayout>,
        { wrapper: createWrapper() }
      );

      const footer = container.querySelector('footer');
      expect(footer).toHaveClass('bg-gray-100');
      expect(footer).toHaveClass('dark:bg-gray-800');
    });

    it('should apply padding to footer', () => {
      const { container } = render(
        <PublicSiteLayout business={mockBusiness}>
          <div>Content</div>
        </PublicSiteLayout>,
        { wrapper: createWrapper() }
      );

      const footer = container.querySelector('footer');
      expect(footer).toHaveClass('py-6');
      expect(footer).toHaveClass('mt-12');
    });

    it('should center footer text', () => {
      const { container } = render(
        <PublicSiteLayout business={mockBusiness}>
          <div>Content</div>
        </PublicSiteLayout>,
        { wrapper: createWrapper() }
      );

      const footer = container.querySelector('footer');
      const footerContent = footer?.querySelector('div');
      expect(footerContent).toHaveClass('text-center');
      expect(footerContent).toHaveClass('text-sm');
    });
  });

  describe('Scroll Behavior', () => {
    it('should call useScrollToTop hook', async () => {
      // Get the mocked module
      const { useScrollToTop: mockUseScrollToTop } = await import('../../hooks/useScrollToTop');

      render(
        <PublicSiteLayout business={mockBusiness}>
          <div>Content</div>
        </PublicSiteLayout>,
        { wrapper: createWrapper() }
      );

      expect(mockUseScrollToTop).toHaveBeenCalled();
    });

    it('should call useScrollToTop on each render', async () => {
      // Get the mocked module
      const { useScrollToTop: mockUseScrollToTop } = await import('../../hooks/useScrollToTop');

      // Clear previous calls
      vi.mocked(mockUseScrollToTop).mockClear();

      const { rerender } = render(
        <PublicSiteLayout business={mockBusiness}>
          <div>Content</div>
        </PublicSiteLayout>,
        { wrapper: createWrapper() }
      );

      expect(mockUseScrollToTop).toHaveBeenCalledTimes(1);

      rerender(
        <PublicSiteLayout business={mockBusiness}>
          <div>New Content</div>
        </PublicSiteLayout>
      );

      expect(mockUseScrollToTop).toHaveBeenCalledTimes(2);
    });
  });

  describe('Integration', () => {
    it('should render complete layout with all sections', () => {
      const business = createMockBusiness({
        name: 'Complete Business',
        primaryColor: '#3B82F6',
        websitePages: {
          '/about': { name: 'About', content: [] },
          '/services': { name: 'Services', content: [] },
        },
      });

      const { container } = render(
        <PublicSiteLayout business={business}>
          <h1>Main Content</h1>
          <p>This is the main content</p>
        </PublicSiteLayout>,
        { wrapper: createWrapper() }
      );

      // Header exists with branding
      const header = container.querySelector('header');
      expect(header).toBeInTheDocument();
      expect(screen.getByText('Complete Business')).toBeInTheDocument();
      expect(screen.getByText('CO')).toBeInTheDocument();

      // Navigation links exist
      expect(screen.getByRole('link', { name: 'About' })).toBeInTheDocument();
      expect(screen.getByRole('link', { name: 'Services' })).toBeInTheDocument();
      expect(screen.getByRole('link', { name: /customer login/i })).toBeInTheDocument();

      // Main content exists
      expect(screen.getByText('Main Content')).toBeInTheDocument();
      expect(screen.getByText('This is the main content')).toBeInTheDocument();

      // Footer exists with copyright
      const currentYear = new Date().getFullYear();
      expect(
        screen.getByText(`© ${currentYear} Complete Business. All Rights Reserved.`)
      ).toBeInTheDocument();
    });

    it('should handle different business configurations', () => {
      const business1 = createMockBusiness({
        name: 'Business A',
        primaryColor: '#FF0000',
        websitePages: undefined,
      });

      const { rerender } = render(
        <PublicSiteLayout business={business1}>
          <div>Content A</div>
        </PublicSiteLayout>,
        { wrapper: createWrapper() }
      );

      expect(screen.getByText('Business A')).toBeInTheDocument();
      expect(screen.getByText('Content A')).toBeInTheDocument();

      const business2 = createMockBusiness({
        name: 'Business B',
        primaryColor: '#00FF00',
        websitePages: {
          '/home': { name: 'Home', content: [] },
        },
      });

      rerender(
        <PublicSiteLayout business={business2}>
          <div>Content B</div>
        </PublicSiteLayout>
      );

      expect(screen.getByText('Business B')).toBeInTheDocument();
      expect(screen.getByText('Content B')).toBeInTheDocument();
      expect(screen.getByRole('link', { name: 'Home' })).toBeInTheDocument();
    });
  });

  describe('Edge Cases', () => {
    it('should handle business with single character name', () => {
      const business = createMockBusiness({ name: 'X' });
      render(
        <PublicSiteLayout business={business}>
          <div>Content</div>
        </PublicSiteLayout>,
        { wrapper: createWrapper() }
      );

      // Single character name appears in both header and footer
      const matches = screen.getAllByText('X');
      expect(matches.length).toBeGreaterThan(0);
    });

    it('should handle business with very long name', () => {
      const business = createMockBusiness({
        name: 'Very Long Business Name That Should Still Work Properly',
      });
      render(
        <PublicSiteLayout business={business}>
          <div>Content</div>
        </PublicSiteLayout>,
        { wrapper: createWrapper() }
      );

      expect(
        screen.getByText('Very Long Business Name That Should Still Work Properly')
      ).toBeInTheDocument();
      expect(screen.getByText('VE')).toBeInTheDocument();
    });

    it('should handle empty children', () => {
      render(
        <PublicSiteLayout business={mockBusiness}>
          {null}
        </PublicSiteLayout>,
        { wrapper: createWrapper() }
      );

      const main = screen.getByRole('main');
      expect(main).toBeInTheDocument();
    });

    it('should handle many website pages', () => {
      const business = createMockBusiness({
        websitePages: {
          '/page1': { name: 'Page 1', content: [] },
          '/page2': { name: 'Page 2', content: [] },
          '/page3': { name: 'Page 3', content: [] },
          '/page4': { name: 'Page 4', content: [] },
          '/page5': { name: 'Page 5', content: [] },
        },
      });

      render(
        <PublicSiteLayout business={business}>
          <div>Content</div>
        </PublicSiteLayout>,
        { wrapper: createWrapper() }
      );

      expect(screen.getByRole('link', { name: 'Page 1' })).toBeInTheDocument();
      expect(screen.getByRole('link', { name: 'Page 2' })).toBeInTheDocument();
      expect(screen.getByRole('link', { name: 'Page 3' })).toBeInTheDocument();
      expect(screen.getByRole('link', { name: 'Page 4' })).toBeInTheDocument();
      expect(screen.getByRole('link', { name: 'Page 5' })).toBeInTheDocument();
    });
  });
});
