(function (root, factory) {
  const api = factory();
  if (typeof module === 'object' && module.exports) module.exports = api;
  else root.createMobileFindWorkNavigation = api;
})(typeof globalThis !== 'undefined' ? globalThis : this, function () {
  'use strict';

  const stages = ['discover', 'review', 'fit'];

  return function createMobileFindWorkNavigation(options) {
    const document = options.document;
    const buttons = options.buttons || Object.fromEntries(stages.map(name =>
      [name, document?.querySelector('[data-find-work-stage="' + name + '"]')]
    ));
    const sections = options.sections || Object.fromEntries(stages.map(name =>
      [name, document?.getElementById('find-work-' + name + '-stage')]
    ));
    const history = options.history;
    const eventTarget = options.eventTarget;
    const onStageChange = options.onStageChange || (() => {});
    const listeners = new Map();
    let current = 'discover';
    let selectedCount = 0;
    let recovery = false;
    let started = false;

    function escape(value) {
      return String(value || '').replace(/[&<>"']/g, character =>
        ({ '&':'&amp;', '<':'&lt;', '>':'&gt;', '"':'&quot;', "'":'&#39;' })[character]
      );
    }

    function renderReview() {
      const reviewList = options.reviewList || document?.getElementById('find-work-review-list');
      const reviewSummary = options.reviewSummary || document?.getElementById('find-work-review-summary');
      if (!reviewList) return;
      const items = options.controller?.selectedItems?.() || options.getSelectedItems?.() || [];
      const planning = options.todayWork?.planning?.();
      const today = options.todayWork ? {
        limit:options.todayWork.limit, count:options.todayWork.read().length,
        capacityMinutes:planning.capacity_minutes, estimates:planning.estimates,
      } : options.getTodayState?.() || {};
      const remainingSlots = Math.max(0, (Number(today.limit) || 0) - (Number(today.count) || 0));
      const planned = Object.values(today.estimates || {}).reduce((sum, minutes) => sum + minutes, 0);
      const remainingMinutes = today.capacityMinutes === null || today.capacityMinutes === undefined ? null :
        Math.max(0, today.capacityMinutes - planned);
      const formatMinutes = minutes => [Math.floor(minutes / 60) ? Math.floor(minutes / 60) + 'h' : '',
        minutes % 60 ? minutes % 60 + 'm' : ''].filter(Boolean).join(' ') || '0m';
      if (reviewSummary) reviewSummary.textContent = items.length + ' selected · ' + remainingSlots +
        ' Today slot' + (remainingSlots === 1 ? '' : 's') + ' open' +
        (remainingMinutes === null ? '' : ' · ' + formatMinutes(remainingMinutes) + ' available') + '.';
      reviewList.innerHTML = items.map(item => {
        const id = String(item.repository || '') + '#' + String(item.number || '');
        return '<article class="find-work-review-item"><div><span class="small">' + escape(id) +
          '</span><strong>' + escape(item.title || 'Untitled work') + '</strong></div>' +
          '<button type="button" data-find-work-review-remove="' + escape(id) + '">Remove</button></article>';
      }).join('');
      reviewList.querySelectorAll('[data-find-work-review-remove]').forEach(button =>
        button.addEventListener('click', () => {
          const item = items.find(candidate => String(candidate.repository || '') + '#' +
            String(candidate.number || '') === button.dataset.findWorkReviewRemove);
          if (item) (options.controller?.toggleSelection || options.toggleSelection)?.(item);
        })
      );
    }

    function allowed(name) {
      return stages.includes(name) && (name === 'discover' || selectedCount > 0 || recovery);
    }

    function paint(name, focus = false, notify = true) {
      if (!allowed(name)) name = 'discover';
      current = name;
      stages.forEach(stage => {
        const button = buttons[stage];
        const section = sections[stage];
        if (button) {
          button.disabled = stage !== 'discover' && selectedCount === 0 && !recovery;
          if (stage === name) button.setAttribute('aria-current', 'step');
          else button.removeAttribute('aria-current');
        }
        if (section) section.hidden = stage !== name;
      });
      if (name === 'review') renderReview();
      if (name === 'fit') options.openFit?.(options.controller?.selectedItems?.() || []);
      if (notify) onStageChange(name);
      if (focus) sections[name]?.focus?.();
      return name;
    }

    function stateFor(name) {
      const state = { ...(history?.state || {}) };
      if (name === 'discover') delete state.findWorkStage;
      else state.findWorkStage = name;
      return state;
    }

    function go(name) {
      if (!allowed(name) || name === current) return false;
      const currentIndex = stages.indexOf(current);
      const nextIndex = stages.indexOf(name);
      if (nextIndex < currentIndex && history?.go) {
        history.go(nextIndex - currentIndex);
        return true;
      }
      if (nextIndex === currentIndex - 1 && history?.back) {
        history.back();
        return true;
      }
      history?.pushState?.(stateFor(name), '');
      paint(name, true);
      return true;
    }

    function onPopState(event) {
      if (event.state?.taskOverlay !== 'find') return;
      paint(event.state?.findWorkStage || 'discover', true);
    }

    function sync(state = {}) {
      selectedCount = Math.max(0, Number(state.selectedCount) || 0);
      recovery = state.recovery === true;
      if (!allowed(current)) paint('discover');
      else paint(current, false, false);
    }

    function open(hasRecovery) {
      if (options.controller) {
        selectedCount = options.controller.selection().count;
        recovery = hasRecovery === true;
      }
      const restored = history?.state?.taskOverlay === 'find' ? history.state.findWorkStage : null;
      return paint(allowed(restored) ? restored : 'discover');
    }

    function complete() {
      selectedCount = 0;
      recovery = false;
      history?.replaceState?.(stateFor('discover'), '');
      return paint('discover');
    }

    function back() {
      if (current === 'discover') return false;
      history?.back?.();
      return true;
    }

    return {
      start() {
        if (started) return;
        started = true;
        stages.forEach(name => {
          const button = buttons[name];
          if (!button) return;
          const listener = event => { event.preventDefault(); go(name); };
          listeners.set(button, listener);
          button.addEventListener('click', listener);
        });
        if (document) {
          const bind = (id, action) => {
            const button = document.getElementById(id);
            if (!button) return;
            const listener = event => { event.preventDefault(); action(); };
            listeners.set(button, listener);
            button.addEventListener('click', listener);
          };
          bind('select-find-work', () => { complete(); options.controller?.startSelection?.(); });
          bind('cancel-find-work-selection', () => { complete(); options.controller?.cancelSelection?.(); });
          bind('claim-selected-work', () => go('review'));
          bind('continue-find-work-fit', () => go('fit'));
          bind('back-find-work-discover', back);
          bind('cancel-find-work-estimates', back);
          bind('close-find-work', () => history?.go?.(-(stages.indexOf(current) + 1)));
        }
        eventTarget?.addEventListener?.('popstate', onPopState);
        paint('discover');
      },
      stop() {
        listeners.forEach((listener, button) => button.removeEventListener('click', listener));
        listeners.clear();
        eventTarget?.removeEventListener?.('popstate', onPopState);
        started = false;
      },
      sync,
      open,
      go,
      back,
      complete,
      renderReview,
      stage: () => current,
    };
  };
});
