/**
 * DealerTemplate Integration Tests
 *
 * Tests BEHAVIOR of the public dealer landing page:
 * - Dealer info displays correctly
 * - Contact form shows/hides based on props
 * - Navigation renders with dropdowns
 * - US vs CA domain handling
 * - JSON-LD schema generation
 *
 * Philosophy: Test what the user sees, not implementation details.
 */

import { render, screen, RenderOptions } from '@testing-library/react';
import { ReactElement } from 'react';
import { DealerTemplate, generateDealerSchema } from '../DealerTemplate';
import { LanguageProvider } from '../LanguageProvider';
import { DealerInfo } from '@/types/dealer';

// Wrapper that provides LanguageProvider context for tests
const renderWithLanguageProvider = (
  ui: ReactElement,
  { subdomain = 'testdealer', ...options }: RenderOptions & { subdomain?: string } = {}
) => {
  const Wrapper = ({ children }: { children: React.ReactNode }) => (
    <LanguageProvider defaultLanguage="en" subdomain={subdomain}>
      {children}
    </LanguageProvider>
  );
  return render(ui, { wrapper: Wrapper, ...options });
};

// Mock sessionStorage for LanguageProvider
const mockSessionStorage = (() => {
  let store: Record<string, string> = {};
  return {
    getItem: (key: string) => store[key] || null,
    setItem: (key: string, value: string) => {
      store[key] = value;
    },
    clear: () => {
      store = {};
    },
  };
})();
Object.defineProperty(window, 'sessionStorage', { value: mockSessionStorage });

// Mock document.cookie for LanguageProvider
let mockCookie = '';
Object.defineProperty(document, 'cookie', {
  get: () => mockCookie,
  set: (value: string) => {
    mockCookie = value;
  },
});

// Mock Next.js Image component
jest.mock('next/image', () => ({
  __esModule: true,
  default: ({ src, alt, ...props }: { src: string; alt: string }) => (
    // eslint-disable-next-line @next/next/no-img-element
    <img src={src} alt={alt} {...props} />
  ),
}));

// Mock HeroSlider to avoid Swiper ESM issues
// Renders button URLs as data attributes so slider pipeline tests can inspect them
jest.mock('@/components/HeroSlider', () => ({
  __esModule: true,
  HeroSlider: ({
    sliderContent,
  }: {
    sliderContent: { slides?: Array<{ button?: { url?: string } }> };
  }) => {
    const urls = sliderContent?.slides?.map((s) => s.button?.url).filter(Boolean) || [];
    return (
      <div data-testid="hero-slider" data-slider-urls={JSON.stringify(urls)}>
        Hero Slider ({sliderContent ? 'with content' : 'empty'})
      </div>
    );
  },
}));

// Mock ContactSection to isolate DealerTemplate tests
jest.mock('@/app/components/contact-section', () => ({
  __esModule: true,
  default: ({ isEnabled, dealerName }: { isEnabled: boolean; dealerName: string }) =>
    isEnabled ? <div data-testid="contact-section">Contact {dealerName}</div> : null,
}));

describe('DealerTemplate', () => {
  const baseDealer: DealerInfo = {
    subdomain: 'testdealer',
    domain: 'com',
    name: 'Test Dealer LLC',
    phone: '(555) 123-4567',
    email: 'test@example.com',
    address: {
      city: 'Springfield',
      state: 'IL',
      zip: '62701',
      street: '123 Main St',
      country: 'United States',
    },
  };

  describe('Dealer Info Display', () => {
    it('renders dealer name in header and dealer info section', () => {
      renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      // Dealer name appears in header (h1) and dealer info section
      const nameElements = screen.getAllByText('Test Dealer LLC');
      expect(nameElements.length).toBeGreaterThanOrEqual(2);
    });

    it('renders phone number with tel: link', () => {
      renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      const phoneLinks = screen.getAllByText('(555) 123-4567');
      expect(phoneLinks.length).toBeGreaterThan(0);

      // Verify at least one is a clickable tel: link (using E.164 format for href)
      const telLink = phoneLinks.find(
        (el) => el.closest('a')?.getAttribute('href') === 'tel:+15551234567'
      );
      expect(telLink).toBeTruthy();
    });

    it('renders city and state in multiple locations', () => {
      renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      // City/state appears in header and address sections
      const cityStateElements = screen.getAllByText(/Springfield, IL/);
      expect(cityStateElements.length).toBeGreaterThanOrEqual(2);
    });

    it('renders full address when not hidden', () => {
      renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      expect(screen.getByText('123 Main St')).toBeInTheDocument();
      // Address appears in multiple places
      const addressElements = screen.getAllByText(/Springfield, IL 62701/);
      expect(addressElements.length).toBeGreaterThan(0);
    });

    it('hides street address when hideAddress is true', () => {
      const dealerWithHiddenAddress = {
        ...baseDealer,
        hideAddress: true,
      };

      renderWithLanguageProvider(<DealerTemplate dealer={dealerWithHiddenAddress} />);

      // Street should not appear
      expect(screen.queryByText('123 Main St')).not.toBeInTheDocument();
      // But city/state/zip still appears in footer
      const footerAddress = screen.getAllByText(/Springfield, IL 62701/);
      expect(footerAddress.length).toBeGreaterThan(0);
    });

    it('renders custom description when provided', () => {
      const dealerWithDescription = {
        ...baseDealer,
        description: 'Your trusted AMSOIL dealer since 1995.',
      };

      renderWithLanguageProvider(<DealerTemplate dealer={dealerWithDescription} />);

      expect(screen.getByText('Your trusted AMSOIL dealer since 1995.')).toBeInTheDocument();
    });

    it('renders default description when none provided', () => {
      renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      expect(screen.getByText(/Not Sure Which Product Is Right For You/)).toBeInTheDocument();
    });
  });

  describe('Contact Form', () => {
    it('shows contact section when leadFormEnabled is true (default)', () => {
      renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      expect(screen.getByTestId('contact-section')).toBeInTheDocument();
    });

    it('hides contact section when leadFormEnabled is false', () => {
      renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} leadFormEnabled={false} />);

      expect(screen.queryByTestId('contact-section')).not.toBeInTheDocument();
    });

    it('hides "GET IN TOUCH" button when leadFormEnabled is false', () => {
      renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} leadFormEnabled={false} />);

      expect(screen.queryByText(/GET IN TOUCH/i)).not.toBeInTheDocument();
    });
  });

  describe('Navigation', () => {
    it('renders navigation items when provided', () => {
      const dealerWithNav = {
        ...baseDealer,
        navigation: [
          { label: 'Products', href: 'https://www.amsoil.com/products', openInNewTab: true },
          { label: 'About', href: '/about', openInNewTab: false },
        ],
      };

      renderWithLanguageProvider(<DealerTemplate dealer={dealerWithNav} />);

      // Nav items appear in both desktop nav and mobile nav
      expect(screen.getAllByText('Products').length).toBeGreaterThan(0);
      expect(screen.getAllByText('About').length).toBeGreaterThan(0);
    });

    it('renders dropdown indicator for items with children', () => {
      const dealerWithDropdown = {
        ...baseDealer,
        navigation: [
          {
            label: 'Products',
            href: null,
            children: [
              { label: 'Motor Oil', href: 'https://www.amsoil.com/motor-oil' },
              { label: 'Filters', href: 'https://www.amsoil.com/filters' },
            ],
          },
        ],
      };

      const { container } = renderWithLanguageProvider(
        <DealerTemplate dealer={dealerWithDropdown} />
      );

      // Parent item appears in both desktop nav and mobile nav
      expect(screen.getAllByText('Products').length).toBeGreaterThan(0);
      // Desktop nav shows dropdown indicator (mobile nav uses chevron icon)
      expect(screen.getByText('▾')).toBeInTheDocument();

      // Child items exist in DOM (may be hidden via CSS until hover/tap)
      const motorOilLink = container.querySelector('a[href*="motor-oil"]');
      const filtersLink = container.querySelector('a[href*="filters"]');
      expect(motorOilLink).toBeInTheDocument();
      expect(filtersLink).toBeInTheDocument();
    });

    it('does not render navigation when not provided', () => {
      renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      // Navigation section should not render when no navigation items
      expect(screen.queryByRole('navigation')).not.toBeInTheDocument();
    });
  });

  describe('US vs Canadian Domain Handling', () => {
    it('renders amsoil.com links for US dealers', () => {
      renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} dealerNumber="123456" />);

      // Footer disclaimer should reference amsoil.com
      expect(screen.getByText(/amsoil.com/)).toBeInTheDocument();
    });

    it('renders amsoil.ca links for Canadian dealers', () => {
      const canadianDealer = {
        ...baseDealer,
        domain: 'ca' as const,
      };

      renderWithLanguageProvider(<DealerTemplate dealer={canadianDealer} dealerNumber="123456" />);

      // Footer disclaimer should reference amsoil.ca
      expect(screen.getByText(/amsoil.ca/)).toBeInTheDocument();
    });
  });

  describe('JSON-LD Schema', () => {
    it('includes JSON-LD script tag', () => {
      const { container } = renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      const schemaScript = container.querySelector('script[type="application/ld+json"]');
      expect(schemaScript).toBeInTheDocument();
    });

    it('includes dealer info in schema', () => {
      const { container } = renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      const schemaScript = container.querySelector('script[type="application/ld+json"]');
      const schema = JSON.parse(schemaScript?.textContent || '{}');

      // Find the LocalBusiness entry
      const localBusiness = schema['@graph']?.find(
        (item: Record<string, unknown>) => item['@type'] === 'AutoPartsStore'
      );

      expect(localBusiness).toBeDefined();
      expect(localBusiness.name).toContain('Test Dealer LLC');
      expect(localBusiness.telephone).toBe('(555) 123-4567');
    });

    it('generates correct URL for US dealers', () => {
      const { container } = renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      const schemaScript = container.querySelector('script[type="application/ld+json"]');
      const schema = JSON.parse(schemaScript?.textContent || '{}');

      const localBusiness = schema['@graph']?.find(
        (item: Record<string, unknown>) => item['@type'] === 'AutoPartsStore'
      );

      expect(localBusiness.url).toContain('myamsoil.com');
      expect(localBusiness.url).not.toMatch(/\/$/); // matches the no-slash canonical
    });

    it('generates correct URL for Canadian dealers', () => {
      const canadianDealer = {
        ...baseDealer,
        domain: 'ca' as const,
      };

      const { container } = renderWithLanguageProvider(<DealerTemplate dealer={canadianDealer} />);

      const schemaScript = container.querySelector('script[type="application/ld+json"]');
      const schema = JSON.parse(schemaScript?.textContent || '{}');

      const localBusiness = schema['@graph']?.find(
        (item: Record<string, unknown>) => item['@type'] === 'AutoPartsStore'
      );

      expect(localBusiness.url).toContain('myamsoil.ca');
      expect(localBusiness.url).not.toMatch(/\/$/); // matches the no-slash canonical
    });

    it('uses dealer.domainPrefix in schema URLs (shopamsoil, not hardcoded myamsoil)', () => {
      // Shopamsoil dealers must NOT emit "myamsoil" in their structured data —
      // that would point search engines at a sibling's site and hurt the
      // dealer's knowledge-graph presence.
      const shopamsoilDealer: DealerInfo = {
        ...baseDealer,
        domainPrefix: 'shopamsoil',
      };

      const { container } = renderWithLanguageProvider(
        <DealerTemplate dealer={shopamsoilDealer} />
      );

      const schemaScript = container.querySelector('script[type="application/ld+json"]');
      const schema = JSON.parse(schemaScript?.textContent || '{}');

      const localBusiness = schema['@graph']?.find(
        (item: Record<string, unknown>) => item['@type'] === 'AutoPartsStore'
      );

      expect(localBusiness.url).toContain('shopamsoil.com');
      expect(localBusiness.url).not.toContain('myamsoil');
      expect(localBusiness['@id']).toContain('shopamsoil.com');
    });

    it('uses dealer.domainPrefix in schema URLs for Canadian shopamsoil dealers', () => {
      const shopamsoilCanadian: DealerInfo = {
        ...baseDealer,
        domain: 'ca' as const,
        domainPrefix: 'shopamsoil',
      };

      const { container } = renderWithLanguageProvider(
        <DealerTemplate dealer={shopamsoilCanadian} />
      );

      const schemaScript = container.querySelector('script[type="application/ld+json"]');
      const schema = JSON.parse(schemaScript?.textContent || '{}');

      const webSite = schema['@graph']?.find(
        (item: Record<string, unknown>) => item['@type'] === 'WebSite'
      );

      expect(webSite.url).toContain('shopamsoil.ca');
      expect(webSite.url).not.toContain('myamsoil');
    });

    it('includes WebSite node with dealer name for Google site name signal', () => {
      const { container } = renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      const schemaScript = container.querySelector('script[type="application/ld+json"]');
      const schema = JSON.parse(schemaScript?.textContent || '{}');

      const webSite = schema['@graph']?.find(
        (item: Record<string, unknown>) => item['@type'] === 'WebSite'
      );

      expect(webSite).toBeDefined();
      expect(webSite.name).toBe('Test Dealer LLC');
      expect(webSite['@id']).toContain('/#website');
      expect(webSite.publisher?.['@id']).toContain('/#localbusiness');
    });

    it('links WebPage to WebSite via isPartOf', () => {
      const { container } = renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      const schemaScript = container.querySelector('script[type="application/ld+json"]');
      const schema = JSON.parse(schemaScript?.textContent || '{}');

      const webPage = schema['@graph']?.find(
        (item: Record<string, unknown>) => item['@type'] === 'WebPage'
      );

      expect(webPage.isPartOf?.['@id']).toContain('/#website');
      expect(webPage.about?.['@id']).toContain('/#localbusiness');
    });
  });

  describe('Quick Links', () => {
    it('renders quick links when provided', () => {
      const dealerWithQuickLinks = {
        ...baseDealer,
        quickLinks: [
          { label: 'Shop Now', href: 'https://www.amsoil.com/shop', openInNewTab: true },
          { label: 'Find Products', href: 'https://www.amsoil.com/lookup', openInNewTab: true },
        ],
      };

      renderWithLanguageProvider(<DealerTemplate dealer={dealerWithQuickLinks} />);

      expect(screen.getByText('Shop Now')).toBeInTheDocument();
      expect(screen.getByText('Find Products')).toBeInTheDocument();
    });

    it('does not render quick links section when not provided', () => {
      renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      // QuickLinks component should not render anything
      expect(screen.queryByText('Shop Now')).not.toBeInTheDocument();
    });
  });

  describe('Dealer Number (ZO) Parameter', () => {
    it('defaults to ZO 101 when dealerNumber not provided', () => {
      const { container } = renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      // Should use default zo=101
      const defaultZoLink = container.querySelector('a[href*="zo=101"]');
      expect(defaultZoLink).toBeInTheDocument();
    });

    it('includes ZO parameter in ALL clickable AMSOIL links (regression test)', () => {
      const { container } = renderWithLanguageProvider(
        <DealerTemplate dealer={baseDealer} dealerNumber="123456" />
      );

      // Get all anchor tags with amsoil.com or amsoil.ca in href
      const allAmsoilLinks = container.querySelectorAll(
        'a[href*="amsoil.com"], a[href*="amsoil.ca"]'
      );

      // Ensure we found some links to test
      expect(allAmsoilLinks.length).toBeGreaterThan(0);

      // Every AMSOIL link should include the zo parameter
      const linksWithoutZo: string[] = [];
      allAmsoilLinks.forEach((link) => {
        const href = link.getAttribute('href') || '';
        if (!href.includes('zo=')) {
          linksWithoutZo.push(href);
        }
      });

      // Fail with helpful message showing which links are missing zo parameter
      expect(linksWithoutZo).toEqual([]);
    });
  });

  describe('Product Categories Section', () => {
    it('renders all vehicle category links', () => {
      const { container } = renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      // All 9 vehicle lookup categories should be present as span labels
      const categoryLabels = container.querySelectorAll('.category-icons span');
      const labelTexts = Array.from(categoryLabels).map((el) => el.textContent);

      expect(labelTexts).toContain('Auto/LT');
      expect(labelTexts).toContain('Motorcycle');
      expect(labelTexts).toContain('ATV');
      expect(labelTexts).toContain('UTV');
      expect(labelTexts).toContain('Snowmobile');
      expect(labelTexts).toContain('Marine');
      expect(labelTexts).toContain('PWC');
      expect(labelTexts).toContain('Small Engine');
      expect(labelTexts).toContain('Heavy Duty');
      expect(categoryLabels.length).toBe(9);
    });

    it('includes ZO parameter in all category links', () => {
      const { container } = renderWithLanguageProvider(
        <DealerTemplate dealer={baseDealer} dealerNumber="123456" />
      );

      // All category links should have zo parameter
      const categoryLinks = container.querySelectorAll('.category-icons a');
      expect(categoryLinks.length).toBe(9);

      categoryLinks.forEach((link) => {
        expect(link.getAttribute('href')).toContain('zo=123456');
      });
    });

    it('opens category links in new tab with security attributes', () => {
      const { container } = renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      const categoryLinks = container.querySelectorAll('.category-icons a');
      categoryLinks.forEach((link) => {
        expect(link).toHaveAttribute('target', '_blank');
        // ZO-attributed AMSOIL links are compensated -> rel="sponsored"
        expect(link).toHaveAttribute('rel', 'sponsored noopener noreferrer');
      });
    });
  });

  describe('Preferred Customer Section', () => {
    it('renders all 6 benefits', () => {
      renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      const benefits = [
        'Reduced Pricing',
        'FREE Shipping',
        'Birthday Gift',
        '$5 Back',
        'Exclusive Promotions',
        'Free Membership',
      ];

      benefits.forEach((benefit) => {
        expect(screen.getByText(benefit)).toBeInTheDocument();
      });
    });

    it('renders JOIN & START SAVING CTA button', () => {
      renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      expect(screen.getByText('JOIN & START SAVING!')).toBeInTheDocument();
    });

    it('includes ZO parameter in PC signup link', () => {
      renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} dealerNumber="999888" />);

      const joinButton = screen.getByText('JOIN & START SAVING!');
      const link = joinButton.closest('a');
      expect(link?.getAttribute('href')).toContain('zo=999888');
    });
  });

  describe('Google Maps Link', () => {
    it('generates Google Maps search link with full address', () => {
      const { container } = renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      const mapsLink = container.querySelector('a[href*="google.com/maps"]');
      expect(mapsLink).toBeInTheDocument();

      const href = mapsLink?.getAttribute('href') || '';
      expect(href).toContain('123%20Main%20St'); // URL-encoded street
      expect(href).toContain('Springfield');
      expect(href).toContain('IL');
      expect(href).toContain('62701');
    });

    it('excludes street address from Maps link when hideAddress is true', () => {
      const dealerHiddenAddress = {
        ...baseDealer,
        hideAddress: true,
      };

      const { container } = renderWithLanguageProvider(
        <DealerTemplate dealer={dealerHiddenAddress} />
      );

      const mapsLink = container.querySelector('a[href*="google.com/maps"]');
      const href = mapsLink?.getAttribute('href') || '';

      // Should NOT contain street
      expect(href).not.toContain('123%20Main%20St');
      // But should contain city/state/zip
      expect(href).toContain('Springfield');
      expect(href).toContain('IL');
      expect(href).toContain('62701');
    });
  });

  describe('Navigation URL Resolution', () => {
    it('appends ZO parameter to AMSOIL navigation links', () => {
      const dealerWithNav = {
        ...baseDealer,
        navigation: [
          {
            label: 'Shop Products',
            href: 'https://www.amsoil.com/shop',
            openInNewTab: true,
          },
        ],
      };

      const { container } = renderWithLanguageProvider(
        <DealerTemplate dealer={dealerWithNav} dealerNumber="555666" />
      );

      const navLink = container.querySelector('.dealer-nav a');
      expect(navLink?.getAttribute('href')).toContain('zo=555666');
    });

    it('resolves amsoil.com to amsoil.ca for Canadian dealers', () => {
      const canadianDealerWithNav = {
        ...baseDealer,
        domain: 'ca' as const,
        navigation: [
          {
            label: 'Shop Products',
            href: 'https://www.amsoil.com/shop',
            openInNewTab: true,
          },
        ],
      };

      const { container } = renderWithLanguageProvider(
        <DealerTemplate dealer={canadianDealerWithNav} />
      );

      const navLink = container.querySelector('.dealer-nav a');
      expect(navLink?.getAttribute('href')).toContain('amsoil.ca');
    });

    it('preserves non-AMSOIL navigation links unchanged', () => {
      const dealerWithExternalNav = {
        ...baseDealer,
        navigation: [
          {
            label: 'My Website',
            href: 'https://mywebsite.com/about',
            openInNewTab: true,
          },
        ],
      };

      const { container } = renderWithLanguageProvider(
        <DealerTemplate dealer={dealerWithExternalNav} />
      );

      const navLink = container.querySelector('.dealer-nav a');
      expect(navLink?.getAttribute('href')).toBe('https://mywebsite.com/about');
      expect(navLink?.getAttribute('href')).not.toContain('zo=');
    });
  });

  describe('Default HeroSlider', () => {
    it('renders hero slider with default content when dealer has no custom slider', () => {
      renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      // HeroSlider should be rendered (mocked)
      expect(screen.getByTestId('hero-slider')).toBeInTheDocument();
    });

    it('renders hero slider when dealer provides custom slider content', () => {
      const dealerWithSlider = {
        ...baseDealer,
        heroSlider: {
          slides: [
            {
              id: 'custom-1',
              image: { url: '/custom-hero.jpg' },
              headline: 'Custom Headline',
              subheading: 'Custom subheading',
              alignment: 'left' as const,
              button: { text: 'Shop', url: 'https://amsoil.com' },
            },
          ],
        },
      };

      renderWithLanguageProvider(<DealerTemplate dealer={dealerWithSlider} />);

      expect(screen.getByTestId('hero-slider')).toBeInTheDocument();
    });
  });

  describe('Page Structure', () => {
    it('renders FIND YOUR PRODUCTS section heading', () => {
      renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      expect(screen.getByText('FIND YOUR PRODUCTS')).toBeInTheDocument();
    });

    it('renders PICK A CATEGORY TO SHOP section heading', () => {
      renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      expect(screen.getByText('PICK A CATEGORY TO SHOP')).toBeInTheDocument();
    });

    it('renders BECOME A PREFERRED CUSTOMER section heading', () => {
      renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      expect(screen.getByText('BECOME A PREFERRED CUSTOMER AND SAVE')).toBeInTheDocument();
    });

    it('renders REQUEST YOUR FREE CATALOG button', () => {
      renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      expect(screen.getByText('REQUEST YOUR FREE CATALOG')).toBeInTheDocument();
    });

    it('renders dynamic copyright year in footer', () => {
      renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      const currentYear = new Date().getFullYear().toString();
      expect(screen.getByText(new RegExp(`AMSOIL INC\\. ${currentYear}`))).toBeInTheDocument();
    });
  });

  describe('Dealer Logo Display', () => {
    it('renders dealer logo when logoUrl is provided', () => {
      const dealerWithLogo = {
        ...baseDealer,
        logoUrl: '/uploads/dealers/abc123/logo.png',
      };

      const { container } = renderWithLanguageProvider(<DealerTemplate dealer={dealerWithLogo} />);

      const logoImg = container.querySelector('.dealer-logo');
      expect(logoImg).toBeInTheDocument();
      expect(logoImg).toHaveAttribute('src', '/uploads/dealers/abc123/logo.png');
    });

    it('does not render dealer logo when logoUrl is null', () => {
      const dealerWithoutLogo = {
        ...baseDealer,
        logoUrl: null,
      };

      const { container } = renderWithLanguageProvider(
        <DealerTemplate dealer={dealerWithoutLogo} />
      );

      expect(container.querySelector('.dealer-logo')).not.toBeInTheDocument();
    });

    it('does not render dealer logo when logoUrl is undefined', () => {
      // baseDealer has no logoUrl property
      const { container } = renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      expect(container.querySelector('.dealer-logo')).not.toBeInTheDocument();
    });

    it('renders logo before dealer name in header', () => {
      const dealerWithLogo = {
        ...baseDealer,
        logoUrl: '/logo.png',
      };

      const { container } = renderWithLanguageProvider(<DealerTemplate dealer={dealerWithLogo} />);

      const nameRow = container.querySelector('.dealer-name-row');
      expect(nameRow).toBeInTheDocument();

      // Logo should be first child, then dealer name
      const children = nameRow?.children;
      expect(children?.[0]).toHaveClass('dealer-logo');
      expect(children?.[1]).toHaveClass('dealer-name');
    });

    it('includes descriptive alt text for dealer logo', () => {
      const dealerWithLogo = {
        ...baseDealer,
        logoUrl: '/logo.png',
      };

      const { container } = renderWithLanguageProvider(<DealerTemplate dealer={dealerWithLogo} />);

      const logoImg = container.querySelector('.dealer-logo');
      expect(logoImg).toHaveAttribute('alt', `${baseDealer.name} logo`);
    });
  });

  describe('Accessibility', () => {
    it('includes alt text for all vehicle category images', () => {
      const { container } = renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      const categoryImages = container.querySelectorAll('.category-icons img');
      expect(categoryImages.length).toBe(9);

      categoryImages.forEach((img) => {
        expect(img).toHaveAttribute('alt');
        expect(img.getAttribute('alt')).not.toBe('');
      });
    });

    it('includes alt text for benefit images', () => {
      const { container } = renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      const benefitImages = container.querySelectorAll('.benefit-icon img');
      expect(benefitImages.length).toBe(6);

      benefitImages.forEach((img) => {
        expect(img).toHaveAttribute('alt');
        expect(img.getAttribute('alt')).not.toBe('');
      });
    });

    it('phone links use tel: protocol', () => {
      const { container } = renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      const telLinks = container.querySelectorAll('a[href^="tel:"]');
      expect(telLinks.length).toBeGreaterThan(0);
    });

    it('renders a <main> landmark wrapping the primary content', () => {
      renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

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

    it('emits h3 (not h4) for preferred-customer benefits and footer column headings', () => {
      const { container } = renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      const benefitHeadings = container.querySelectorAll('.preferred-customer .benefit h3');
      expect(benefitHeadings.length).toBe(6);

      const footerHeadings = container.querySelectorAll('.footer-column h3');
      expect(footerHeadings.length).toBe(3);

      expect(container.querySelectorAll('.preferred-customer .benefit h4').length).toBe(0);
      expect(container.querySelectorAll('.footer-column h4').length).toBe(0);
    });
  });

  describe('Header Home Links', () => {
    it('both header links have aria-labels', () => {
      const { container } = renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      const homeLinks = container.querySelectorAll('a[aria-label="Go to home page"]');
      expect(homeLinks.length).toBe(2);
    });

    it('AMSOIL branding row links to home page', () => {
      const { container } = renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      const brandingLink = container.querySelector('.header-logo');
      expect(brandingLink?.tagName).toBe('A');
      expect(brandingLink?.getAttribute('href')).toBe('/');
    });

    it('dealer name row links to home page', () => {
      const { container } = renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      const nameLink = container.querySelector('.dealer-name-row');
      expect(nameLink?.tagName).toBe('A');
      expect(nameLink?.getAttribute('href')).toBe('/');
    });

    it('AMSOIL branding link contains INDEPENDENT DEALER text', () => {
      const { container } = renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      const brandingLink = container.querySelector('.header-logo');
      expect(brandingLink?.textContent).toContain('INDEPENDENT DEALER');
    });

    it('dealer name link contains the dealer business name', () => {
      const { container } = renderWithLanguageProvider(<DealerTemplate dealer={baseDealer} />);

      const nameLink = container.querySelector('.dealer-name-row');
      expect(nameLink?.textContent).toContain('Test Dealer LLC');
    });
  });

  describe('Canadian Dealer + ZO Combined', () => {
    const canadianDealer: DealerInfo = {
      ...baseDealer,
      domain: 'ca' as const,
      address: {
        ...baseDealer.address,
        country: 'Canada',
      },
    };

    it('renders amsoil.ca links WITH ZO parameter for Canadian dealers', () => {
      const { container } = renderWithLanguageProvider(
        <DealerTemplate dealer={canadianDealer} dealerNumber="654321" />
      );

      const allAmsoilLinks = container.querySelectorAll(
        'a[href*="amsoil.com"], a[href*="amsoil.ca"]'
      );

      expect(allAmsoilLinks.length).toBeGreaterThan(0);

      allAmsoilLinks.forEach((link) => {
        const href = link.getAttribute('href') || '';
        // All AMSOIL links should use .ca domain
        expect(href).toContain('amsoil.ca');
        expect(href).not.toContain('amsoil.com');
        // AND all should include the ZO number
        expect(href).toContain('zo=654321');
      });
    });

    it('uses Canadian category IDs with ZO in product lookup links', () => {
      const { container } = renderWithLanguageProvider(
        <DealerTemplate dealer={canadianDealer} dealerNumber="654321" />
      );

      // Category links should use Canadian IDs (US IDs + 300)
      const categoryLinks = container.querySelectorAll('.category-icons a');
      expect(categoryLinks.length).toBeGreaterThan(0);

      categoryLinks.forEach((link) => {
        const href = link.getAttribute('href') || '';
        expect(href).toContain('amsoil.ca');
        expect(href).toContain('zo=654321');
      });
    });

    it('resolves Canadian nav links with ZO parameter', () => {
      const canadianWithNav = {
        ...canadianDealer,
        navigation: [
          {
            label: 'Shop Products',
            href: 'https://www.amsoil.com/c/products/1/',
            openInNewTab: true,
          },
        ],
      };

      const { container } = renderWithLanguageProvider(
        <DealerTemplate dealer={canadianWithNav} dealerNumber="654321" />
      );

      const navLink = container.querySelector('.dealer-nav a');
      const href = navLink?.getAttribute('href') || '';
      expect(href).toContain('amsoil.ca');
      expect(href).not.toContain('amsoil.com');
      expect(href).toContain('zo=654321');
    });
  });

  describe('Fragment Handling in ZO URLs', () => {
    it('places zo= BEFORE fragment in navigation links', () => {
      const dealerWithFragmentNav = {
        ...baseDealer,
        navigation: [
          {
            label: 'Products',
            href: 'https://www.amsoil.com/products/#motor-oil',
            openInNewTab: true,
          },
        ],
      };

      const { container } = renderWithLanguageProvider(
        <DealerTemplate dealer={dealerWithFragmentNav} dealerNumber="123456" />
      );

      const navLink = container.querySelector('.dealer-nav a');
      const href = navLink?.getAttribute('href') || '';

      // ZO should come before the fragment
      expect(href).toContain('?zo=123456#motor-oil');
      // Fragment should NOT come before zo
      expect(href).not.toMatch(/#motor-oil.*zo=/);
    });

    it('handles nav links with query params AND fragment', () => {
      const dealerWithParamsAndFragment = {
        ...baseDealer,
        navigation: [
          {
            label: 'Search',
            href: 'https://www.amsoil.com/search?cat=1#results',
            openInNewTab: true,
          },
        ],
      };

      const { container } = renderWithLanguageProvider(
        <DealerTemplate dealer={dealerWithParamsAndFragment} dealerNumber="123456" />
      );

      const navLink = container.querySelector('.dealer-nav a');
      const href = navLink?.getAttribute('href') || '';

      // Should use & separator and place zo before fragment
      expect(href).toContain('?cat=1&zo=123456#results');
    });
  });

  describe('Canadian Dealer Slider URL Pipeline', () => {
    it('resolves default slider URLs to amsoil.ca with ZO for Canadian dealers', () => {
      const canadianDealer: DealerInfo = {
        ...baseDealer,
        domain: 'ca' as const,
      };

      const { container } = renderWithLanguageProvider(
        <DealerTemplate dealer={canadianDealer} dealerNumber="654321" />
      );

      const slider = container.querySelector('[data-testid="hero-slider"]');
      expect(slider).not.toBeNull();

      const urlsJson = slider?.getAttribute('data-slider-urls') || '[]';
      const urls: string[] = JSON.parse(urlsJson);

      // Default slider has 6 slides with AMSOIL URLs
      expect(urls.length).toBe(6);

      urls.forEach((url) => {
        // All should use amsoil.ca (not amsoil.com)
        expect(url).toContain('amsoil.ca');
        expect(url).not.toContain('amsoil.com');
        // All should have ZO parameter
        expect(url).toContain('zo=654321');
        // No duplicate zo= params
        const zoCount = (url.match(/zo=/g) || []).length;
        expect(zoCount).toBe(1);
      });
    });

    it('uses Canadian category IDs in slider URLs', () => {
      const canadianDealer: DealerInfo = {
        ...baseDealer,
        domain: 'ca' as const,
      };

      const { container } = renderWithLanguageProvider(
        <DealerTemplate dealer={canadianDealer} dealerNumber="654321" />
      );

      const slider = container.querySelector('[data-testid="hero-slider"]');
      const urlsJson = slider?.getAttribute('data-slider-urls') || '[]';
      const urls: string[] = JSON.parse(urlsJson);

      // Default slides use US IDs: 4, 111, 5, 104, 108, 110
      // Canadian equivalents: 304, 411, 305, 404, 408, 410
      const expectedCanadianIds = ['304', '411', '305', '404', '408', '410'];
      expectedCanadianIds.forEach((id) => {
        const hasId = urls.some((url) => url.includes(`/${id}/`));
        expect(hasId).toBe(true);
      });
    });
  });
});

const baseDealerInfo: DealerInfo = {
  subdomain: 'testdealer',
  domain: 'com',
  domainPrefix: 'myamsoil',
  name: 'Test Dealer',
  phone: '+15551234567',
  email: 'test@example.com',
  address: {
    city: 'Minneapolis',
    state: 'MN',
    zip: '55401',
    street: '123 Main St',
    country: 'US',
  },
  description: '<p>Test description</p>',
  navigation: [],
  heroSlider: null,
  quickLinks: [],
  hideAddress: false,
  contactName: 'Test',
  showContactName: false,
  logoUrl: undefined,
  headScripts: undefined,
  bodyScripts: undefined,
  socialLinks: undefined,
  preferredLanguage: 'en',
  amsoilLinkDomain: 'com',
};

describe('generateDealerSchema', () => {
  it('returns valid JSON-LD with @context and @graph', () => {
    const schema = generateDealerSchema(baseDealerInfo) as Record<string, unknown>;
    expect(schema['@context']).toBe('https://schema.org');
    expect(Array.isArray(schema['@graph'])).toBe(true);
  });

  it('does not contain Product nodes', () => {
    const schema = generateDealerSchema(baseDealerInfo) as { '@graph': Record<string, unknown>[] };
    const productNodes = schema['@graph'].filter((n) => n['@type'] === 'Product');
    expect(productNodes).toHaveLength(0);
  });

  it('does not include makesOffer on AutoPartsStore', () => {
    const schema = generateDealerSchema(baseDealerInfo) as { '@graph': Record<string, unknown>[] };
    const store = schema['@graph'].find((n) => n['@type'] === 'AutoPartsStore') as Record<
      string,
      unknown
    >;
    expect(store).toBeDefined();
    expect(store['makesOffer']).toBeUndefined();
  });

  it('produces @id values without double slashes', () => {
    const schema = generateDealerSchema(baseDealerInfo) as { '@graph': Record<string, unknown>[] };
    const json = JSON.stringify(schema);
    expect(json).not.toContain('///#');
    expect(json).not.toContain('myamsoil.com//#');
  });

  it('AutoPartsStore @id uses correct URL format', () => {
    const schema = generateDealerSchema(baseDealerInfo) as { '@graph': Record<string, unknown>[] };
    const store = schema['@graph'].find((n) => n['@type'] === 'AutoPartsStore') as Record<
      string,
      unknown
    >;
    expect(store['@id']).toBe('https://testdealer.myamsoil.com/#localbusiness');
  });

  it('includes image pointing to the /og OG image URL', () => {
    const schema = generateDealerSchema(baseDealerInfo) as { '@graph': Record<string, unknown>[] };
    const store = schema['@graph'].find((n) => n['@type'] === 'AutoPartsStore') as Record<
      string,
      unknown
    >;
    expect(store['image']).toBe('https://testdealer.myamsoil.com/og');
  });

  it('includes priceRange', () => {
    const schema = generateDealerSchema(baseDealerInfo) as { '@graph': Record<string, unknown>[] };
    const store = schema['@graph'].find((n) => n['@type'] === 'AutoPartsStore') as Record<
      string,
      unknown
    >;
    expect(store['priceRange']).toBe('$-$$$');
  });

  it('includes hasMap with street when hideAddress is false', () => {
    const schema = generateDealerSchema(baseDealerInfo) as { '@graph': Record<string, unknown>[] };
    const store = schema['@graph'].find((n) => n['@type'] === 'AutoPartsStore') as Record<
      string,
      unknown
    >;
    expect(typeof store['hasMap']).toBe('string');
    expect(store['hasMap'] as string).toContain('google.com/maps');
    expect(store['hasMap'] as string).toContain(encodeURIComponent('123 Main St'));
  });

  it('includes city-level hasMap when hideAddress is true (no street)', () => {
    const schema = generateDealerSchema({ ...baseDealerInfo, hideAddress: true }) as {
      '@graph': Record<string, unknown>[];
    };
    const store = schema['@graph'].find((n) => n['@type'] === 'AutoPartsStore') as Record<
      string,
      unknown
    >;
    expect(typeof store['hasMap']).toBe('string');
    expect(store['hasMap'] as string).toContain(encodeURIComponent('Minneapolis'));
    expect(store['hasMap'] as string).not.toContain(encodeURIComponent('123 Main St'));
  });

  it('includes streetAddress in PostalAddress when hideAddress is false', () => {
    const schema = generateDealerSchema(baseDealerInfo) as { '@graph': Record<string, unknown>[] };
    const store = schema['@graph'].find((n) => n['@type'] === 'AutoPartsStore') as Record<
      string,
      unknown
    >;
    const address = store['address'] as Record<string, unknown>;
    expect(address['streetAddress']).toBe('123 Main St');
  });

  it('omits streetAddress from PostalAddress when hideAddress is true', () => {
    const schema = generateDealerSchema({ ...baseDealerInfo, hideAddress: true }) as {
      '@graph': Record<string, unknown>[];
    };
    const store = schema['@graph'].find((n) => n['@type'] === 'AutoPartsStore') as Record<
      string,
      unknown
    >;
    const address = store['address'] as Record<string, unknown>;
    expect(address['streetAddress']).toBeUndefined();
    // city/state/zip still present — hideAddress only hides the street
    expect(address['addressLocality']).toBe('Minneapolis');
    expect(address['addressRegion']).toBe('MN');
  });

  it('includes logo when logoUrl is set', () => {
    const schema = generateDealerSchema({
      ...baseDealerInfo,
      logoUrl: 'https://cdn.example.com/logo.png',
    }) as { '@graph': Record<string, unknown>[] };
    const store = schema['@graph'].find((n) => n['@type'] === 'AutoPartsStore') as Record<
      string,
      unknown
    >;
    expect(store['logo']).toBe('https://cdn.example.com/logo.png');
  });

  it('omits logo when logoUrl is not set', () => {
    const schema = generateDealerSchema(baseDealerInfo) as { '@graph': Record<string, unknown>[] };
    const store = schema['@graph'].find((n) => n['@type'] === 'AutoPartsStore') as Record<
      string,
      unknown
    >;
    expect(store['logo']).toBeUndefined();
  });

  it('includes sameAs array when social links are present', () => {
    const dealer = {
      ...baseDealerInfo,
      socialLinks: {
        facebook: 'https://facebook.com/testdealer',
        instagram: 'https://instagram.com/testdealer',
      },
    };
    const schema = generateDealerSchema(dealer) as { '@graph': Record<string, unknown>[] };
    const store = schema['@graph'].find((n) => n['@type'] === 'AutoPartsStore') as Record<
      string,
      unknown
    >;
    expect(Array.isArray(store['sameAs'])).toBe(true);
    expect(store['sameAs']).toContain('https://facebook.com/testdealer');
    expect(store['sameAs']).toContain('https://instagram.com/testdealer');
  });

  it('omits sameAs when no social links are set', () => {
    const schema = generateDealerSchema(baseDealerInfo) as { '@graph': Record<string, unknown>[] };
    const store = schema['@graph'].find((n) => n['@type'] === 'AutoPartsStore') as Record<
      string,
      unknown
    >;
    expect(store['sameAs']).toBeUndefined();
  });

  it('emits a Person (dealer) entity when contact name is provided AND shown', () => {
    const schema = generateDealerSchema({
      ...baseDealerInfo,
      contactName: 'Jane Operator',
      showContactName: true,
    }) as { '@graph': Record<string, unknown>[] };
    const person = schema['@graph'].find((n) => n['@type'] === 'Person') as Record<string, unknown>;
    const store = schema['@graph'].find((n) => n['@type'] === 'AutoPartsStore') as Record<
      string,
      unknown
    >;
    expect(person).toBeDefined();
    expect(person['name']).toBe('Jane Operator');
    expect(person['jobTitle']).toBe('Authorized AMSOIL Dealer');
    // Linked both ways: AutoPartsStore.founder <-> Person.worksFor
    expect((person['worksFor'] as Record<string, unknown>)['@id']).toBe(store['@id']);
    expect((store['founder'] as Record<string, unknown>)['@id']).toBe(person['@id']);
  });

  it('omits the Person entity when the dealer opted NOT to show the contact name', () => {
    const schema = generateDealerSchema({
      ...baseDealerInfo,
      contactName: 'Jane Operator',
      showContactName: false,
    }) as { '@graph': Record<string, unknown>[] };
    const person = schema['@graph'].find((n) => n['@type'] === 'Person');
    const store = schema['@graph'].find((n) => n['@type'] === 'AutoPartsStore') as Record<
      string,
      unknown
    >;
    expect(person).toBeUndefined();
    expect(store['founder']).toBeUndefined();
  });

  it('omits the Person entity when no contact name is set (even if showContactName is true)', () => {
    const schema = generateDealerSchema({
      ...baseDealerInfo,
      contactName: undefined,
      showContactName: true,
    }) as { '@graph': Record<string, unknown>[] };
    const person = schema['@graph'].find((n) => n['@type'] === 'Person');
    const store = schema['@graph'].find((n) => n['@type'] === 'AutoPartsStore') as Record<
      string,
      unknown
    >;
    expect(person).toBeUndefined();
    expect(store['founder']).toBeUndefined();
  });

  it('does not assert brand on the LocalBusiness (dealer does not own the AMSOIL brand)', () => {
    const schema = generateDealerSchema(baseDealerInfo) as { '@graph': Record<string, unknown>[] };
    const store = schema['@graph'].find((n) => n['@type'] === 'AutoPartsStore') as Record<
      string,
      unknown
    >;
    expect(store['brand']).toBeUndefined();
    const brandNodes = schema['@graph'].filter((n) => {
      const t = n['@type'];
      return t === 'Brand' || (Array.isArray(t) && t.includes('Brand'));
    });
    expect(brandNodes).toHaveLength(0);
  });

  it('models authorized-dealer status as a credential recognized by AMSOIL', () => {
    const schema = generateDealerSchema(baseDealerInfo) as { '@graph': Record<string, unknown>[] };
    const store = schema['@graph'].find((n) => n['@type'] === 'AutoPartsStore') as Record<
      string,
      unknown
    >;
    const cred = store['hasCredential'] as Record<string, unknown>;
    expect(cred).toBeDefined();
    expect(cred['@type']).toBe('EducationalOccupationalCredential');
    expect(cred['name']).toBe('Authorized AMSOIL Dealer');
    expect(cred['credentialCategory']).toBe('Authorized Dealer');
    const amsoil = schema['@graph'].find((n) => n['@type'] === 'Organization') as Record<
      string,
      unknown
    >;
    expect(amsoil).toBeDefined();
    expect(amsoil['name']).toBe('AMSOIL INC.');
    expect((cred['recognizedBy'] as Record<string, unknown>)['@id']).toBe(amsoil['@id']);
  });

  it('includes email when the dealer has one and omits it when blank', () => {
    const withEmail = generateDealerSchema(baseDealerInfo) as {
      '@graph': Record<string, unknown>[];
    };
    const store1 = withEmail['@graph'].find((n) => n['@type'] === 'AutoPartsStore') as Record<
      string,
      unknown
    >;
    expect(store1['email']).toBe('test@example.com');

    const noEmail = generateDealerSchema({ ...baseDealerInfo, email: '' }) as {
      '@graph': Record<string, unknown>[];
    };
    const store2 = noEmail['@graph'].find((n) => n['@type'] === 'AutoPartsStore') as Record<
      string,
      unknown
    >;
    expect(store2['email']).toBeUndefined();
  });

  it('declares knowsAbout topics linked to Wikipedia entities', () => {
    const schema = generateDealerSchema(baseDealerInfo) as { '@graph': Record<string, unknown>[] };
    const store = schema['@graph'].find((n) => n['@type'] === 'AutoPartsStore') as Record<
      string,
      unknown
    >;
    const topics = store['knowsAbout'] as Array<Record<string, unknown>>;
    expect(Array.isArray(topics)).toBe(true);
    expect(topics.length).toBeGreaterThan(0);
    // every topic is a Thing with a name and a Wikipedia sameAs link
    expect(
      topics.every(
        (t) =>
          t['@type'] === 'Thing' &&
          typeof t['name'] === 'string' &&
          String(t['sameAs']).startsWith('https://en.wikipedia.org/wiki/')
      )
    ).toBe(true);
    expect(topics.map((t) => t['name'])).toContain('Synthetic oil');
  });

  it('includes a disambiguatingDescription distinguishing the dealer from AMSOIL corp', () => {
    const schema = generateDealerSchema(baseDealerInfo) as { '@graph': Record<string, unknown>[] };
    const store = schema['@graph'].find((n) => n['@type'] === 'AutoPartsStore') as Record<
      string,
      unknown
    >;
    expect(store['disambiguatingDescription']).toContain('Independent, authorized AMSOIL dealer');
  });
});
