/*!
 * Copyright (c) 2023 Eclipse Foundation, Inc.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * Contributors:
 *   Olivier Goulet <olivier.goulet@eclipse-foundation.org>
 *
 * SPDX-License-Identifier: EPL-2.0
 */

import eclipsefdnHeader from '../astro/eclipsefdn.header';
import { waitForRender } from '../../utils/utils';

const defaultHeaderTemplateOptions = {
  hideMenuTarget: false,
  hideMenuTargetDataAttribute: false,
}

/**
  * Utility function to generate a header template for tests.
  */
const headerTemplate = ({ hideMenuTarget, hideMenuTargetDataAttribute } = defaultHeaderTemplateOptions) => `
  <header>
    <nav>
      <ul>
        <li>
          <button class="nav-link-js" ${hideMenuTargetDataAttribute ? '' : 'data-menu-target="projects-menu"'}>
            Projects
          </button>
        </li>
      </ul>
    </nav>
    <nav class="mobile-menu hidden">
      <ul>
        <li class="mobile-menu-dropdown">
          <a href="#" class="mobile-menu-item mobile-menu-dropdown-toggle" ${hideMenuTargetDataAttribute ? '' : 'data-target="projects-menu"'}>
            Projects
          </a>
          <div class="mobile-menu-sub-menu-wrapper">
            <ul class="mobile-menu-sub-menu hidden" id="projects-menu">
               
            </ul>
          </div>
        </li>
        <li class="mobile-menu-dropdown">
          <!-- For a test case where no target exist -->
          <a href="#" class="mobile-menu-item mobile-menu-dropdown-toggle" data-target="does-not-exist">
            Does not exist
          </a>
        </li>
      </ul>
    </nav>
    <div class="eclipsefdn-mega-menu">
      ${
        hideMenuTarget 
          ? '' 
          : '<div class="mega-menu-submenu container hidden" data-menu-id="projects-menu">'
      }
      </div>
    </div>
    <button class="mobile-menu-btn"></button>
  </header>
`;

describe('eclipsefdn.header', () => {
  describe('Mega Menu', () => {
    it('Should not crash nor error if no header element is found', () => {
      // Suppress console.error output
      jest.spyOn(console, 'error').mockImplementation(() => {});

      eclipsefdnHeader.run();
      
      expect(console.error).not.toHaveBeenCalled();

      // Restore console.error
      console.error.mockRestore();
    });

    it('Mega menu should toggle when a nav item is clicked', async () => {
      document.querySelector('body').innerHTML = headerTemplate();
      await waitForRender(document.body);

      eclipsefdnHeader.run();
      
      const projectsMenuElement = document.querySelector('.mega-menu-submenu[data-menu-id="projects-menu"]');
      const projectNavLinkElement = document.querySelector('.nav-link-js[data-menu-target="projects-menu"]'); 
      
      // Expect menu to be hidden by default
      expect(projectsMenuElement.classList.contains('hidden')).toBe(true);

      // Click to show
      projectNavLinkElement.click();
      // Expect menu to be visible after one click
      expect(projectsMenuElement.classList.contains('hidden')).toBe(false);

      // Click again to hide
      projectNavLinkElement.click();
      // Expect menu to be hidden after two clicks
      expect(projectsMenuElement.classList.contains('hidden')).toBe(true);
    });

    it('Should display an error if a nav item element is missing a menu target data attribute', async () => {
      // Suppress console.error output
      jest.spyOn(console, 'error').mockImplementation(() => {});

      document.body.innerHTML = headerTemplate({ hideMenuTargetDataAttribute: true });

      await waitForRender(document.body);

      eclipsefdnHeader.run();

      const projectNavLinkElement = document.querySelector('.nav-link-js');
      projectNavLinkElement.click();

      expect(console.error).toHaveBeenCalledWith(
        expect.stringContaining('missing menu target')
      );

      // Restore console.error
      console.error.mockRestore();
    });

    it('Should hide the mega menu when user clicks outside', async () => {
      document.body.innerHTML = headerTemplate();
      document.body.innerHTML += `<div class="outside"></div>`;

      await waitForRender(document.body);

      eclipsefdnHeader.run();

      const projectsMenuElement = document.querySelector('.mega-menu-submenu[data-menu-id="projects-menu"]');
      const projectNavLinkElement = document.querySelector('.nav-link-js[data-menu-target="projects-menu"]'); 

      // Click to show
      projectNavLinkElement.click();
      expect(projectsMenuElement.classList.contains('hidden')).toBe(false);

      // Click outside to hide
      document.querySelector('.outside').click();
      expect(projectsMenuElement.classList.contains('hidden')).toBe(true);
    });
  });

  describe('Mobile Menu', () => {
    it('Should toggle the mobile menu when the hamburger button is clicked', async () => {
      document.body.innerHTML = headerTemplate();
      await waitForRender(document.body);

      eclipsefdnHeader.run();

      const mobileMenuElement = document.querySelector('.mobile-menu');
      const mobileMenuButtonElement = document.querySelector('.mobile-menu-btn');
      
      // Expect menu to be hidden by default
      expect(mobileMenuElement.classList.contains('hidden')).toBe(true);

      // Expect menu to be visible after one click
      mobileMenuButtonElement.click();
      expect(mobileMenuElement.classList.contains('hidden')).toBe(false);

      // Expect menu to be hidden when button clicked while visible
      mobileMenuButtonElement.click();
      expect(mobileMenuElement.classList.contains('hidden')).toBe(true); 
      
      // Click again to show
      mobileMenuButtonElement.click();
      expect(mobileMenuElement.classList.contains('hidden')).toBe(false);
    });

    it('Should open a mobile menu dropdown when a mobile menu item is clicked', async () => {
      document.body.innerHTML = headerTemplate();
      await waitForRender(document.body);

      eclipsefdnHeader.run();

      const mobileMenuDropdownElement = document.querySelector('.mobile-menu-sub-menu#projects-menu');
      const mobileMenuItemElement = document.querySelector('.mobile-menu-dropdown-toggle[data-target="projects-menu"]');

      // Expect dropdown to be hidden by default
      expect(mobileMenuDropdownElement.classList.contains('hidden')).toBe(true);

      // Click to show
      mobileMenuItemElement.click();
      expect(mobileMenuDropdownElement.classList.contains('hidden')).toBe(false);

      // Click again to hide
      mobileMenuItemElement.click();
      expect(mobileMenuDropdownElement.classList.contains('hidden')).toBe(true);
    });

    it('Should log an error if a mobile menu dropdown is missing a target', async () => {
      document.body.innerHTML = headerTemplate({ hideMenuTargetDataAttribute: true });
      await waitForRender(document.body);

      // Suppress console.error output
      jest.spyOn(console, 'error').mockImplementation(() => {});
      
      eclipsefdnHeader.run();

      const mobileMenuItemElement = document.querySelector('.mobile-menu-dropdown-toggle');
      mobileMenuItemElement.click();

      expect(console.error).toHaveBeenCalledWith(
        expect.stringContaining('No toggle target id')
      );

      // Restore console.error
      console.error.mockRestore();
    });

    it('Should log an error if target could not be found for a mobile menu dropdown', async () => {
      document.body.innerHTML = headerTemplate();
      await waitForRender(document.body);

      // Suppress console.error output
      jest.spyOn(console, 'error').mockImplementation(() => {});
      
      eclipsefdnHeader.run();

      const mobileMenuItemElement = document.querySelector('.mobile-menu-dropdown-toggle[data-target="does-not-exist"]');
      mobileMenuItemElement.click();

      expect(console.error).toHaveBeenCalledWith(
        expect.stringContaining('Could not find toggle target')
      );

      // Restore console.error
      console.error.mockRestore(); 
    });
  });
});
