import './style.css';

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

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

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

  parent.querySelectorAll(':scope > li.bdt-parent.is-open').forEach((sibling) => {
    if (sibling !== item) {
      sibling.classList.remove('is-open');
      sibling.setAttribute('aria-expanded', 'false');
      const siblingTrigger = sibling.querySelector(':scope > a');
      if (siblingTrigger instanceof HTMLElement) {
        siblingTrigger.setAttribute('aria-expanded', 'false');
      }
    }
  });
};

const getAdminBarOffset = () => {
  if (!document.body?.classList.contains('admin-bar')) {
    return 0;
  }

  return window.innerWidth <= 782 ? 46 : 32;
};

const parsePx = (value) => {
  if (typeof value !== 'string' || value.trim() === '') {
    return 0;
  }

  const parsed = Number.parseFloat(value);
  return Number.isFinite(parsed) ? parsed : 0;
};

const findStickyHost = (root) => {
  if (!(root instanceof HTMLElement)) {
    return null;
  }

  let current = root.parentElement;
  while (current instanceof HTMLElement) {
    const isElementorSticky =
      current.classList.contains('elementor-sticky') ||
      current.classList.contains('elementor-sticky--active');

    const computed = window.getComputedStyle(current);
    const isCssSticky = computed.position === 'sticky' || computed.position === 'fixed';

    if (isElementorSticky || isCssSticky) {
      return current;
    }

    current = current.parentElement;
  }

  return null;
};

const initNavbar = (root) => {
  if (!(root instanceof HTMLElement)) {
    return;
  }

  const wrapper = root.closest('.bdt-navbar-wrapper');
  const config = parseConfig(root.getAttribute('data-bdt-navbar'));
  const align = typeof config.align === 'string' ? config.align : 'left';
  const mobileToggleEnabled = Boolean(config['mobile-toggle'])
    && wrapper instanceof HTMLElement
    && wrapper.classList.contains('calio-navbar-mobile-toggle-enabled');
  const parsedBreakpoint = Number(config['mobile-breakpoint']);
  const mobileBreakpoint = Number.isFinite(parsedBreakpoint)
    ? Math.min(Math.max(parsedBreakpoint, 600), 1600)
    : 1024;
  const showDelay = Number(config['delay-show'] || 0);
  const hideDelay = Number(config['delay-hide'] || 240);
  const dropdownOffset = Number(config.offset);
  const dropdownDuration = Number(config.duration);
  const parentItems = Array.from(root.querySelectorAll('li.bdt-parent'));
  const cleanups = [];
  const validAlignments = ['left', 'center', 'right'];
  const isMobileViewport = () => window.matchMedia(`(max-width: ${mobileBreakpoint}px)`).matches;
  const toggleButton = wrapper instanceof HTMLElement
    ? wrapper.querySelector(':scope > .calio-navbar-toggle-wrap > .calio-navbar-toggle')
    : null;

  root.classList.remove(
    'calio-navbar-dropdown-align-left',
    'calio-navbar-dropdown-align-center',
    'calio-navbar-dropdown-align-right',
  );

  root.classList.add(
    `calio-navbar-dropdown-align-${validAlignments.includes(align) ? align : 'left'}`,
  );

  if (Number.isFinite(dropdownOffset)) {
    root.style.setProperty('--calio-navbar-drop-offset', `${Math.max(0, dropdownOffset)}px`);
  }

  if (Number.isFinite(dropdownDuration)) {
    root.style.setProperty('--calio-navbar-drop-duration', `${Math.max(120, dropdownDuration)}ms`);
  }

  const syncStickyOffset = () => {
    const stickyHost = findStickyHost(root);
    const adminOffset = getAdminBarOffset();

    root.style.setProperty('--calio-navbar-admin-offset', `${adminOffset}px`);
    root.classList.toggle('calio-navbar-has-admin-offset', adminOffset > 0);

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

    if (!stickyHost.dataset.calioNavbarOriginalTop) {
      stickyHost.dataset.calioNavbarOriginalTop = stickyHost.style.top || '';
    }

    const inlineTop = stickyHost.dataset.calioNavbarOriginalTop || '';
    const currentTop = inlineTop !== '' ? parsePx(inlineTop) : parsePx(window.getComputedStyle(stickyHost).top);
    const nextTop = adminOffset > 0 ? Math.max(currentTop, adminOffset) : currentTop;

    stickyHost.style.top = nextTop > 0 ? `${nextTop}px` : inlineTop;
    stickyHost.classList.add('calio-navbar-sticky-host');
  };

  let stickySyncFrame = 0;
  const scheduleStickySync = () => {
    if (stickySyncFrame) {
      return;
    }

    stickySyncFrame = window.requestAnimationFrame(() => {
      stickySyncFrame = 0;
      syncStickyOffset();
    });
  };

  syncStickyOffset();

  const on = (element, eventName, handler) => {
    element.addEventListener(eventName, handler);
    cleanups.push(() => element.removeEventListener(eventName, handler));
  };

  const setMobileOpen = (open) => {
    if (!(wrapper instanceof HTMLElement) || !(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');
  };

  const updateViewportState = () => {
    if (!(wrapper instanceof HTMLElement)) {
      return;
    }

    wrapper.classList.toggle('calio-navbar-mobile-view', isMobileViewport());
  };

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

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

  updateViewportState();

  on(window, 'resize', scheduleStickySync);
  on(window, 'scroll', scheduleStickySync);
  on(window, 'resize', () => {
    updateViewportState();
    if (!isMobileViewport()) {
      setMobileOpen(false);
    }
  });

  parentItems.forEach((item) => {
    const dropdown = item.querySelector(':scope > .bdt-navbar-dropdown');
    if (!(dropdown instanceof HTMLElement)) {
      return;
    }

    let showTimer = null;
    let hideTimer = null;

    const clearTimers = () => {
      if (showTimer) {
        window.clearTimeout(showTimer);
        showTimer = null;
      }

      if (hideTimer) {
        window.clearTimeout(hideTimer);
        hideTimer = null;
      }
    };

    const open = () => {
      clearTimers();
      closeSiblings(item);
      item.classList.add('is-open');
      item.setAttribute('aria-expanded', 'true');
      if (trigger instanceof HTMLElement) {
        trigger.setAttribute('aria-expanded', 'true');
      }
    };

    const close = () => {
      clearTimers();
      item.classList.remove('is-open');
      item.setAttribute('aria-expanded', 'false');
      if (trigger instanceof HTMLElement) {
        trigger.setAttribute('aria-expanded', 'false');
      }
    };

    const scheduleOpen = () => {
      clearTimers();
      showTimer = window.setTimeout(open, Math.max(showDelay, 0));
    };

    const scheduleClose = () => {
      clearTimers();
      hideTimer = window.setTimeout(close, Math.max(hideDelay, 0));
    };

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

    const trigger = item.querySelector(':scope > a');
    if (trigger instanceof HTMLElement) {
      if (!dropdown.id) {
        dropdown.id = `calio-navbar-dropdown-${Math.random().toString(36).slice(2, 10)}`;
      }
      trigger.setAttribute('aria-haspopup', 'true');
      trigger.setAttribute('aria-expanded', 'false');
      trigger.setAttribute('aria-controls', dropdown.id);
      item.setAttribute('aria-expanded', 'false');

      on(trigger, 'click', (event) => {
        if (isMobileViewport()) {
          const href = trigger.getAttribute('href') || '';
          const isPlaceholder = href === '#' || href.trim() === '';

          if (!item.classList.contains('is-open')) {
            event.preventDefault();
            open();
            return;
          }

          if (isPlaceholder) {
            event.preventDefault();
            close();
          }
        }
      });

      on(trigger, 'keydown', (event) => {
        if (event.key === 'Escape') {
          close();
          trigger.blur();
          return;
        }

        if (event.key === 'ArrowDown') {
          event.preventDefault();
          open();
          const firstLink = dropdown.querySelector('a');
          if (firstLink instanceof HTMLElement) {
            firstLink.focus();
          }
          return;
        }

        if (event.key === ' ' && trigger.getAttribute('href') === '#') {
          event.preventDefault();
          if (item.classList.contains('is-open')) {
            close();
          } else {
            open();
          }
        }
      });
    }
  });

  const closeAll = () => {
    parentItems.forEach((item) => {
      item.classList.remove('is-open');
      item.setAttribute('aria-expanded', 'false');
      const trigger = item.querySelector(':scope > a');
      if (trigger instanceof HTMLElement) {
        trigger.setAttribute('aria-expanded', 'false');
      }
    });
    setMobileOpen(false);
  };

  on(document, 'click', (event) => {
    if (wrapper instanceof HTMLElement) {
      if (!wrapper.contains(event.target)) {
        closeAll();
      }
    } else if (!root.contains(event.target)) {
      closeAll();
    }
  });

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

    const targetLink = event.target instanceof Element ? event.target.closest('a') : null;
    if (!(targetLink instanceof HTMLElement) || !root.contains(targetLink)) {
      return;
    }

    const parentItem = targetLink.closest('li');
    const hasChildren = parentItem instanceof HTMLElement && parentItem.classList.contains('bdt-parent');
    if (!hasChildren) {
      setMobileOpen(false);
    }
  });

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

  if (root.__calioNavbarDestroy) {
    root.__calioNavbarDestroy();
  }

  root.__calioNavbarDestroy = () => {
    if (stickySyncFrame) {
      window.cancelAnimationFrame(stickySyncFrame);
      stickySyncFrame = 0;
    }
    cleanups.forEach((cleanup) => cleanup());
    root.__calioNavbarDestroy = null;
  };
};

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

  scope.querySelectorAll('.bdt-navbar-container').forEach((navbar) => {
    initNavbar(navbar);
  });
};

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

let calioNavbarHookBound = false;
const bindElementorNavbar = () => {
  if (calioNavbarHookBound) {
    return true;
  }

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

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

  calioNavbarHookBound = true;
  return true;
};

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