import './style.css';

const DEFAULT_AJAX_ACTION = 'calio_megamenu_template';

const parseConfig = (value) => {
  if (!value) {
    return {};
  }

  try {
    return JSON.parse(value);
  } catch (error) {
    return {};
  }
};

const isPlaceholderLink = (href) => {
  const value = String(href || '').trim();
  return value === '' || value === '#';
};

const initMegaMenu = (menu) => {
  if (!(menu instanceof HTMLElement)) {
    return;
  }

  if (typeof menu.__calioMegaDestroy === 'function') {
    menu.__calioMegaDestroy();
  }

  const wrapper = menu.closest('.calio-mega-menu-wrapper');
  if (!(wrapper instanceof HTMLElement)) {
    return;
  }

  const config = parseConfig(menu.getAttribute('data-calio-menu'));
  const interaction = config.interaction === 'click' ? 'click' : 'hover';
  const mobileToggleEnabled = Boolean(config['mobile-toggle'])
    && wrapper.classList.contains('calio-mobile-toggle-enabled');
  const parsedBreakpoint = Number(config['mobile-breakpoint']);
  const mobileBreakpoint = Number.isFinite(parsedBreakpoint)
    ? Math.min(Math.max(parsedBreakpoint, 600), 1600)
    : 1024;
  const ajaxUrl = typeof config['ajax-url'] === 'string' ? config['ajax-url'] : '';
  const ajaxAction = typeof config['ajax-action'] === 'string' && config['ajax-action'] !== ''
    ? config['ajax-action']
    : DEFAULT_AJAX_ACTION;
  const ajaxNonce = typeof config['ajax-nonce'] === 'string' ? config['ajax-nonce'] : '';

  const cleanups = [];
  const hoverTimers = new Map();
  const isOffcanvasLayout = wrapper.classList.contains('calio-mobile-layout-offcanvas-left')
    || wrapper.classList.contains('calio-mobile-layout-offcanvas-right');

  const on = (element, eventName, handler, options) => {
    if (!(element instanceof EventTarget)) {
      return;
    }

    element.addEventListener(eventName, handler, options);
    cleanups.push(() => element.removeEventListener(eventName, handler, options));
  };

  const isMobileViewport = () => window.matchMedia(`(max-width: ${mobileBreakpoint}px)`).matches;
  const overlayLayer = wrapper.querySelector(':scope > .calio-mobile-overlay');

  const syncBodyScrollLock = () => {
    const hasOpenOffcanvas = document.querySelector(
      '.calio-mega-menu-wrapper.calio-is-mobile-view.is-mobile-open.calio-mobile-toggle-enabled.calio-mobile-layout-offcanvas-left, .calio-mega-menu-wrapper.calio-is-mobile-view.is-mobile-open.calio-mobile-toggle-enabled.calio-mobile-layout-offcanvas-right',
    );
    document.body.classList.toggle('calio-mobile-menu-lock', Boolean(hasOpenOffcanvas));
  };

  const menuItems = Array.from(menu.querySelectorAll('.calio-menu-item'));
  const parentItems = menuItems.filter((item) => {
    if (!(item instanceof HTMLElement)) {
      return false;
    }

    return item.classList.contains('calio-has-children')
      || item.classList.contains('calio-has-megamenu')
      || item.querySelector(':scope > .calio-submenu-wrap')
      || item.querySelector(':scope > .calio-megamenu-panel');
  });

  const triggerMap = new WeakMap();

  parentItems.forEach((item) => {
    const trigger = item.querySelector(':scope > a');
    const panel = item.querySelector(':scope > .calio-submenu-wrap, :scope > .calio-megamenu-panel');

    if (!(trigger instanceof HTMLElement)) {
      return;
    }

    triggerMap.set(item, trigger);

    if (panel instanceof HTMLElement) {
      if (!panel.id) {
        panel.id = `calio-mega-panel-${Math.random().toString(36).slice(2, 10)}`;
      }

      trigger.setAttribute('aria-controls', panel.id);
      trigger.setAttribute('aria-haspopup', 'true');
    }

    trigger.setAttribute('aria-expanded', 'false');
  });

  const toggleButton = wrapper.querySelector(':scope > .calio-menu-toggle-wrap > .calio-menu-toggle');

  const setMobileOpen = (open) => {
    if (!(toggleButton instanceof HTMLElement) || !mobileToggleEnabled) {
      return;
    }

    wrapper.classList.toggle('is-mobile-open', open);
    toggleButton.classList.toggle('is-open', open);
    toggleButton.setAttribute('aria-expanded', open ? 'true' : 'false');
    if (overlayLayer instanceof HTMLElement && isOffcanvasLayout) {
      overlayLayer.setAttribute('aria-hidden', open ? 'false' : 'true');
    }
    syncBodyScrollLock();
  };

  const syncItemAria = (item, expanded) => {
    const trigger = triggerMap.get(item);
    if (trigger instanceof HTMLElement) {
      trigger.setAttribute('aria-expanded', expanded ? 'true' : 'false');
    }
  };

  const closeItem = (item, recursive = true) => {
    if (!(item instanceof HTMLElement)) {
      return;
    }

    item.classList.remove('is-open');
    syncItemAria(item, false);

    if (!recursive) {
      return;
    }

    item.querySelectorAll(':scope .calio-menu-item.is-open').forEach((child) => {
      if (!(child instanceof HTMLElement)) {
        return;
      }

      child.classList.remove('is-open');
      syncItemAria(child, false);
    });
  };

  const closeSiblings = (item) => {
    const parent = item?.parentElement;
    if (!(parent instanceof HTMLElement)) {
      return;
    }

    parent.querySelectorAll(':scope > .calio-menu-item.is-open').forEach((sibling) => {
      if (sibling !== item) {
        closeItem(sibling, true);
      }
    });
  };

  const loadPanelContent = (item) => {
    if (!(item instanceof HTMLElement) || ajaxUrl === '' || ajaxNonce === '') {
      return;
    }

    const panel = item.querySelector(':scope > .calio-megamenu-panel[data-ajax-load="yes"]');
    if (!(panel instanceof HTMLElement)) {
      return;
    }

    if (panel.dataset.loaded === 'yes' || panel.dataset.loading === 'yes') {
      return;
    }

    const templateId = Number.parseInt(String(panel.dataset.templateId || ''), 10);
    if (!Number.isFinite(templateId) || templateId <= 0) {
      return;
    }

    const panelInner = panel.querySelector(':scope > .calio-megamenu-panel-inner');

    panel.dataset.loading = 'yes';
    panel.classList.add('is-loading');

    const payload = new URLSearchParams({
      action: ajaxAction,
      template_id: String(templateId),
      _ajax_nonce: ajaxNonce,
    });

    fetch(ajaxUrl, {
      method: 'POST',
      credentials: 'same-origin',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
      },
      body: payload.toString(),
    })
      .then((response) => {
        if (!response.ok) {
          throw new Error('request_failed');
        }
        return response.json();
      })
      .then((result) => {
        if (!result || result.success !== true || !result.data || typeof result.data.html !== 'string') {
          throw new Error('invalid_payload');
        }

        if (panelInner instanceof HTMLElement) {
          panelInner.innerHTML = result.data.html;
        }
        panel.dataset.loaded = 'yes';
      })
      .catch(() => {
        if (panelInner instanceof HTMLElement) {
          const empty = document.createElement('div');
          empty.className = 'calio-mega-empty';
          empty.textContent = 'Unable to load menu content.';
          panelInner.replaceChildren(empty);
        }
        panel.dataset.loaded = 'error';
      })
      .finally(() => {
        delete panel.dataset.loading;
        panel.classList.remove('is-loading');
      });
  };

  const openItem = (item) => {
    if (!(item instanceof HTMLElement)) {
      return;
    }

    closeSiblings(item);
    item.classList.add('is-open');
    syncItemAria(item, true);
    loadPanelContent(item);
  };

  const closeAll = () => {
    parentItems.forEach((item) => closeItem(item, true));
  };

  const setViewportState = () => {
    const mobile = isMobileViewport();
    wrapper.classList.toggle('calio-is-mobile-view', mobile);

    if (!mobile) {
      setMobileOpen(false);
    }
  };

  setViewportState();
  syncBodyScrollLock();

  if (mobileToggleEnabled && toggleButton instanceof HTMLElement) {
    toggleButton.setAttribute('aria-expanded', 'false');
    on(toggleButton, 'click', () => {
      if (!isMobileViewport()) {
        return;
      }

      const nextState = !wrapper.classList.contains('is-mobile-open');
      setMobileOpen(nextState);

      if (!nextState) {
        closeAll();
      }
    });
  }

  if (mobileToggleEnabled && overlayLayer instanceof HTMLElement && isOffcanvasLayout) {
    overlayLayer.setAttribute('aria-hidden', 'true');
    on(overlayLayer, 'click', () => {
      if (!isMobileViewport()) {
        return;
      }
      setMobileOpen(false);
      closeAll();
    });
  }

  parentItems.forEach((item) => {
    const trigger = triggerMap.get(item);

    if (!(trigger instanceof HTMLElement)) {
      return;
    }

    const clearHoverTimer = () => {
      const timer = hoverTimers.get(item);
      if (timer) {
        window.clearTimeout(timer);
        hoverTimers.delete(item);
      }
    };

    if (interaction === 'hover') {
      on(item, 'mouseenter', () => {
        if (isMobileViewport()) {
          return;
        }

        clearHoverTimer();
        openItem(item);
      });

      on(item, 'mouseleave', () => {
        if (isMobileViewport()) {
          return;
        }

        clearHoverTimer();
        const timeout = window.setTimeout(() => {
          closeItem(item, true);
        }, 120);
        hoverTimers.set(item, timeout);
      });
    }

    on(trigger, 'click', (event) => {
      const isMobile = isMobileViewport();
      const href = trigger.getAttribute('href');
      const isPlaceholder = isPlaceholderLink(href);
      const isOpen = item.classList.contains('is-open');

      if (isMobile) {
        if (!isOpen) {
          event.preventDefault();
          openItem(item);
          return;
        }

        if (isPlaceholder) {
          event.preventDefault();
          closeItem(item, true);
        }
        return;
      }

      if (interaction === 'click') {
        if (!isOpen) {
          event.preventDefault();
          openItem(item);
          return;
        }

        if (isPlaceholder) {
          event.preventDefault();
          closeItem(item, true);
        }
        return;
      }

      if (isPlaceholder) {
        event.preventDefault();
        if (isOpen) {
          closeItem(item, true);
        } else {
          openItem(item);
        }
      }
    });

    on(trigger, 'keydown', (event) => {
      if (event.key === 'Escape') {
        event.preventDefault();
        closeItem(item, true);
        trigger.blur();
        return;
      }

      if (event.key === 'ArrowDown') {
        event.preventDefault();
        openItem(item);
        const firstLink = item.querySelector(':scope > .calio-submenu-wrap a, :scope > .calio-megamenu-panel a');
        if (firstLink instanceof HTMLElement) {
          firstLink.focus();
        }
        return;
      }

      if (event.key === 'Enter' || event.key === ' ') {
        if (isPlaceholderLink(trigger.getAttribute('href'))) {
          event.preventDefault();
          if (item.classList.contains('is-open')) {
            closeItem(item, true);
          } else {
            openItem(item);
          }
        }
      }
    });
  });

  on(menu, 'click', (event) => {
    if (!isMobileViewport() || !mobileToggleEnabled) {
      return;
    }

    const target = event.target;
    if (!(target instanceof Element)) {
      return;
    }

    const link = target.closest('a');
    if (!(link instanceof HTMLAnchorElement)) {
      return;
    }

    if (!menu.contains(link)) {
      return;
    }

    const item = link.closest('.calio-menu-item');
    if (!(item instanceof HTMLElement)) {
      return;
    }

    if (item.classList.contains('calio-has-children') || item.classList.contains('calio-has-megamenu')) {
      return;
    }

    setMobileOpen(false);
    closeAll();
  });

  on(document, 'click', (event) => {
    const target = event.target;
    if (!(target instanceof Node)) {
      return;
    }

    if (!wrapper.contains(target)) {
      closeAll();
      setMobileOpen(false);
    }
  });

  on(document, 'keydown', (event) => {
    if (event.key !== 'Escape') {
      return;
    }

    closeAll();
    setMobileOpen(false);
  });

  on(window, 'resize', () => {
    setViewportState();
    closeAll();
    syncBodyScrollLock();
  });

  menu.__calioMegaDestroy = () => {
    setMobileOpen(false);
    hoverTimers.forEach((timer) => window.clearTimeout(timer));
    hoverTimers.clear();
    cleanups.forEach((cleanup) => cleanup());
    syncBodyScrollLock();
    menu.__calioMegaDestroy = null;
  };
};

const boot = (scope = document) => {
  if (!(scope instanceof HTMLElement || scope instanceof Document)) {
    return;
  }

  scope.querySelectorAll('.calio-mega-menu').forEach((menu) => {
    initMegaMenu(menu);
  });
};

document.addEventListener('DOMContentLoaded', () => {
  boot(document);
});

let calioMegaMenuHookBound = false;
const bindElementorMegaMenu = () => {
  if (calioMegaMenuHookBound) {
    return true;
  }

  if (!window.elementorFrontend?.hooks) {
    return false;
  }

  window.elementorFrontend.hooks.addAction('frontend/element_ready/calio-mega-menu.default', ($scope) => {
    const root = $scope?.[0] || document;
    boot(root);
  });

  calioMegaMenuHookBound = true;
  return true;
};

window.addEventListener('elementor/frontend/init', bindElementorMegaMenu);
if (!bindElementorMegaMenu()) {
  let attempts = 0;
  const timer = window.setInterval(() => {
    attempts += 1;
    if (bindElementorMegaMenu() || attempts >= 40) {
      window.clearInterval(timer);
    }
  }, 250);
}
