function createMobileSearchPreviewNavigation(options) {
  const buttons = options.buttons || {};
  const targets = options.targets || {};
  const focusTargets = options.focusTargets || {};
  const listeners = new Map();
  const prefersReducedMotion = options.prefersReducedMotion || (() => false);
  const targetNames = new Map(Object.entries(targets).map(([name, target]) => [target, name]));
  let replyAvailable = options.replyAvailable !== false;
  let observer = null;
  let navigationLockUntil = 0;

  function select(name) {
    Object.entries(buttons).forEach(([key, button]) => {
      if (!button) return;
      if (key === name) button.setAttribute('aria-current', 'location');
      else button.removeAttribute('aria-current');
    });
  }

  function setReplyAvailable(available) {
    replyAvailable = Boolean(available);
    const button = buttons.reply;
    if (!button) return;
    if (replyAvailable) button.removeAttribute('aria-disabled');
    else button.setAttribute('aria-disabled', 'true');
  }

  function navigate(name) {
    if (name === 'reply' && !replyAvailable) return false;
    const target = targets[name];
    if (!target) return false;
    target.scrollIntoView({
      block: 'start',
      behavior: prefersReducedMotion() ? 'auto' : 'smooth',
    });
    navigationLockUntil = Date.now() + 500;
    select(name);
    const focusTarget = focusTargets[name] || (name === 'reply' ? target : null);
    if (focusTarget) focusTarget.focus({preventScroll:true});
    return true;
  }

  function reset(available = replyAvailable) {
    setReplyAvailable(available);
    select('overview');
  }

  return {
    start() {
      Object.entries(buttons).forEach(([name, button]) => {
        if (!button || listeners.has(button)) return;
        const listener = event => {
          event.preventDefault();
          navigate(name);
        };
        listeners.set(button, listener);
        button.addEventListener('click', listener);
      });
      reset(replyAvailable);
      const observe = options.observe || ((handler, observedTargets, root) => {
        if (typeof IntersectionObserver === 'undefined') return null;
        const instance = new IntersectionObserver(handler, {
          root,
          rootMargin: '-20% 0px -60% 0px',
          threshold: [0, 0.25, 0.5, 0.75, 1],
        });
        observedTargets.forEach(target => instance.observe(target));
        return instance;
      });
      observer = observe(entries => {
        if (Date.now() < navigationLockUntil) return;
        const visible = entries
          .filter(entry => entry.isIntersecting && targetNames.has(entry.target))
          .filter(entry => targetNames.get(entry.target) !== 'reply' || replyAvailable)
          .sort((left, right) => right.intersectionRatio - left.intersectionRatio)[0];
        if (visible) select(targetNames.get(visible.target));
      }, Array.from(targetNames.keys()).filter(Boolean), options.root || null);
    },
    stop() {
      listeners.forEach((listener, button) => button.removeEventListener('click', listener));
      listeners.clear();
      if (observer) observer.disconnect();
      observer = null;
    },
    navigate,
    reset,
    select,
    setReplyAvailable,
  };
}

function attachMobileSearchPreviewNavigation({document, window}) {
  const bySection = name => document.querySelector('[data-search-preview-section="' + name + '"]');
  const preview = document.getElementById('search-preview');
  const reply = document.getElementById('search-preview-reply-workspace');
  const navigation = createMobileSearchPreviewNavigation({
    root:document.querySelector('.search-preview-panel'),
    buttons:{
      overview:bySection('overview'),
      conversation:bySection('conversation'),
      reply:bySection('reply'),
      actions:bySection('actions'),
    },
    targets:{
      overview:document.getElementById('search-preview-overview'),
      conversation:document.getElementById('search-preview-conversation'),
      reply,
      actions:document.getElementById('search-preview-actions'),
    },
    focusTargets:{reply:document.getElementById('search-preview-reply')},
    replyAvailable:!reply.hidden,
    prefersReducedMotion:() => window.matchMedia('(prefers-reduced-motion: reduce)').matches,
  });
  navigation.start();
  new MutationObserver(() => navigation.setReplyAvailable(!reply.hidden)).observe(reply, {
    attributes:true, attributeFilter:['hidden'],
  });
  new MutationObserver(() => {
    if (preview.classList.contains('open')) navigation.reset(!reply.hidden);
  }).observe(preview, {attributes:true, attributeFilter:['class']});
  ['previous-search-result', 'next-search-result'].forEach(id => {
    document.getElementById(id).addEventListener('click', () => {
      setTimeout(() => navigation.reset(!reply.hidden), 0);
    });
  });
  return navigation;
}

if (typeof module !== 'undefined') module.exports = createMobileSearchPreviewNavigation;
else attachMobileSearchPreviewNavigation({document, window});
