(function (root, factory) {
  if (typeof module === 'object' && module.exports) module.exports = factory;
  else root.createMobileStartDay = factory;
})(typeof self !== 'undefined' ? self : this, function createMobileStartDay(options) {
  const checkpointKey = 'stackchain.mobile-start-day.v1';
  const storage = options.storage || (typeof localStorage !== 'undefined' ? localStorage : null);
  const reviewOrder = [
    ['delivery', 'Delivery recovery'],
    ['agenda', 'Agenda'],
    ['attention', 'Attention'],
    ['update', 'Updates'],
    ['filed', 'Filed'],
  ];
  const anonymousItems = new WeakMap();
  let anonymousItemSequence = 0;

  function count(value) {
    return Math.max(0, Number(value) || 0);
  }

  function itemIdentity(item) {
    if (item === null || item === undefined) return '';
    if (typeof item !== 'object') return String(item);
    const explicit = item.outbox_id || item.id || item.key || item.url;
    if (explicit !== null && explicit !== undefined && String(explicit)) {
      return String(item.kind || 'item') + ':' + String(explicit);
    }
    if (!anonymousItems.has(item)) anonymousItems.set(item, 'anonymous:' + (++anonymousItemSequence));
    return anonymousItems.get(item);
  }

  function reviewPhases(counts) {
    if (!options.getPhaseItems) {
      return reviewOrder
        .map(([name, label]) => ({name, label, count: count(counts[name])}))
        .filter(phase => phase.count > 0);
    }
    const items = options.getPhaseItems() || {};
    const seen = new Set();
    return reviewOrder.flatMap(([name, label]) => {
      let phaseCount = 0;
      (items[name] || []).forEach(item => {
        const identity = itemIdentity(item);
        if (!identity || seen.has(identity)) return;
        seen.add(identity);
        phaseCount += 1;
      });
      return phaseCount ? [{name, label, count:phaseCount}] : [];
    });
  }

  function localDay() {
    const now = new Date();
    const pad = value => String(value).padStart(2, '0');
    return now.getFullYear() + '-' + pad(now.getMonth() + 1) + '-' + pad(now.getDate());
  }

  function identity() {
    try {
      return {
        login: String(options.getLogin ? options.getLogin() : '').trim(),
        day: String(options.getDay ? options.getDay() : localDay()),
      };
    } catch (_) {
      return {login:'', day:''};
    }
  }

  function checkpoint() {
    if (!storage) return null;
    const current = identity();
    if (!current.login || !current.day) return null;
    try {
      const saved = JSON.parse(storage.getItem(checkpointKey) || 'null');
      return saved?.login === current.login && saved?.day === current.day ? saved : null;
    } catch (_) {
      return null;
    }
  }

  function saveCheckpoint(phase = null) {
    if (!storage) return false;
    const current = identity();
    if (!current.login || !current.day) return false;
    try {
      storage.setItem(checkpointKey, JSON.stringify({...current, phase}));
      return true;
    } catch (_) {
      return false;
    }
  }

  function clearCheckpoint() {
    if (!storage || !checkpoint()) return false;
    try {
      storage.removeItem(checkpointKey);
      return true;
    } catch (_) {
      return false;
    }
  }

  function briefing() {
    const counts = options.getCounts ? options.getCounts() : {};
    const phases = reviewPhases(counts);
    const total = phases.reduce((sum, phase) => sum + phase.count, 0);
    const today = count(counts.today);
    const delivery = phases.find(phase => phase.name === 'delivery')?.count || 0;
    const other = total - delivery;
    const next = phases.length ? phases[0].name : (today ? 'today' : 'find');
    const nextLabel = next === 'delivery' ? 'Review Delivery' :
      (phases.length ? 'Review ' + phases[0].label : (today ? 'Continue Today' : 'Find Work'));
    return {
      total,
      next,
      label: nextLabel,
      summary: delivery ? delivery + (delivery === 1 ? ' delivery needs' : ' deliveries need') +
        ' action before Today' + (other ? ' · ' + other + ' other ' + (other === 1 ? 'item' : 'items') : '') +
        ' · ' + today + ' planned' :
        total ? total + ' items before Today · ' + today + ' planned' :
        (today ? 'Review clear · ' + today + ' planned' : 'Review clear · Today is empty'),
      phases,
    };
  }

  function startNext() {
    const next = briefing().next;
    if (reviewOrder.some(([name]) => name === next)) saveCheckpoint(next);
    else clearCheckpoint();
    options.openQueue(next);
    return next;
  }

  function state() {
    const current = briefing();
    return {active:Boolean(checkpoint()), next:current.next, label:current.label};
  }

  function completePhase(phase) {
    const saved = checkpoint();
    if (!saved || (saved.phase && saved.phase !== phase)) return false;
    const current = render();
    saveCheckpoint();
    if (options.onHandoff) options.onHandoff(current);
    return true;
  }

  function reconcile({authoritative = false, authoritativePhases = []} = {}) {
    const saved = checkpoint();
    if (!saved?.phase || (!authoritative && !authoritativePhases.includes(saved.phase))) return false;
    const counts = options.getCounts ? options.getCounts() : {};
    if (count(counts[saved.phase]) > 0) return false;
    return completePhase(saved.phase);
  }

  function finish() {
    const cleared = clearCheckpoint();
    render();
    return cleared;
  }

  function render() {
    const current = briefing();
    if (!options.elements) return current;
    options.elements.summary.textContent = current.summary;
    options.elements.phases.textContent = current.phases.length ?
      current.phases.map(phase => phase.label + ' ' + phase.count).join(' · ') :
      'All urgent queues reviewed';
    options.elements.action.textContent = checkpoint() ? 'Resume preparation · ' + current.label : current.label;
    if (options.elements.finish) options.elements.finish.hidden = !checkpoint();
    return current;
  }

  function start() {
    render();
    if (options.elements) options.elements.action.addEventListener('click', startNext);
  }

  return {briefing, completePhase, finish, reconcile, render, start, startNext, state};
});
