{{-- Logica condivisa timeline orizzontale (preparazione / ritiro) --}}
<script>
window.AsportoTimeline = (function () {
  const SOON_MINUTES = 10;
  const TIMING_REFRESH_MS = 30000;
  const AUTOSCROLL_MS = 20000;
  const USER_PAUSE_MS = 25000;

  let timelineScroll = null;
  let timeline = null;
  let btnTimelineNow = null;
  let nowCursor = null;
  let nowLabel = null;
  let timelinePausedUntil = 0;
  let nowCursorLeft = 0;
  let started = false;
  let timers = [];
  let abort = null;

  function parseOraDate(ora) {
    const match = String(ora || '').trim().match(/^(\d{1,2}):(\d{2})$/);
    if (!match) return null;
    const d = new Date();
    d.setSeconds(0, 0);
    d.setHours(parseInt(match[1], 10), parseInt(match[2], 10), 0, 0);
    return d;
  }

  function timingInfo(ora) {
    const target = parseOraDate(ora);
    if (!target) return { level: '', label: '', diffMin: null };
    const diffMin = Math.round((target.getTime() - Date.now()) / 60000);
    if (diffMin < 0) {
      return { level: 'late', label: 'Ritardo ' + Math.abs(diffMin) + ' min', diffMin: diffMin };
    }
    if (diffMin === 0) {
      return { level: 'soon', label: 'Adesso', diffMin: 0 };
    }
    if (diffMin <= SOON_MINUTES) {
      return { level: 'soon', label: 'Tra ' + diffMin + ' min', diffMin: diffMin };
    }
    return { level: 'ok', label: 'In orario', diffMin: diffMin };
  }

  function applyTiming(el) {
    if (!el || el.getAttribute('data-stato') === 'consegnato') {
      if (el) {
        el.removeAttribute('data-timing-level');
        el.querySelectorAll('[data-timing-badge]').forEach(function (b) {
          b.textContent = '';
          b.classList.remove('is-visible');
        });
      }
      return null;
    }

    const info = timingInfo(el.getAttribute('data-ora-ritiro'));
    if (!info.level) {
      el.removeAttribute('data-timing-level');
      return null;
    }

    el.setAttribute('data-timing-level', info.level);
    el.querySelectorAll('[data-timing-badge]').forEach(function (b) {
      b.textContent = info.label;
      b.classList.add('is-visible');
    });
    return info;
  }

  function formatClock(date) {
    const h = String(date.getHours()).padStart(2, '0');
    const m = String(date.getMinutes()).padStart(2, '0');
    return h + ':' + m;
  }

  function minutesOfDay(date) {
    return date.getHours() * 60 + date.getMinutes() + date.getSeconds() / 60;
  }

  function itemCenterX(el) {
    return el.offsetLeft + (el.offsetWidth / 2);
  }

  function updateTimelineStats() {
    if (!timeline) return;

    let late = 0;
    let soon = 0;
    let total = 0;

    timeline.querySelectorAll('.asporto-timeline__item').forEach(function (el) {
      total += 1;
      if (el.getAttribute('data-stato') === 'consegnato') return;
      const level = el.getAttribute('data-timing-level');
      if (level === 'late') late += 1;
      if (level === 'soon') soon += 1;
    });

    const lateEl = document.querySelector('[data-tl-late]');
    const soonEl = document.querySelector('[data-tl-soon]');
    const totalEl = document.querySelector('[data-tl-total]');
    const lateWrap = document.getElementById('tl-stat-late');
    const soonWrap = document.getElementById('tl-stat-soon');

    if (lateEl) lateEl.textContent = String(late);
    if (soonEl) soonEl.textContent = String(soon);
    if (totalEl) totalEl.textContent = String(total);
    if (lateWrap) lateWrap.hidden = late === 0;
    if (soonWrap) soonWrap.hidden = soon === 0;
  }

  function updateNowCursor() {
    if (!timeline || !nowCursor) return;

    const items = Array.from(timeline.querySelectorAll('.asporto-timeline__item'))
      .map(function (el) {
        const d = parseOraDate(el.getAttribute('data-ora-ritiro'));
        return d ? { el: el, min: minutesOfDay(d) } : null;
      })
      .filter(Boolean)
      .sort(function (a, b) { return a.min - b.min; });

    const now = new Date();
    if (nowLabel) nowLabel.textContent = formatClock(now);

    if (!items.length) {
      nowCursor.hidden = true;
      return;
    }

    nowCursor.hidden = false;
    timeline.appendChild(nowCursor);

    const nowMin = minutesOfDay(now);
    let left = itemCenterX(items[0].el);

    if (nowMin <= items[0].min) {
      left = items[0].el.offsetLeft;
    } else if (nowMin >= items[items.length - 1].min) {
      const last = items[items.length - 1].el;
      left = last.offsetLeft + last.offsetWidth;
    } else {
      for (let i = 0; i < items.length - 1; i++) {
        const a = items[i];
        const b = items[i + 1];
        if (nowMin >= a.min && nowMin <= b.min) {
          const span = Math.max(b.min - a.min, 0.0001);
          const t = (nowMin - a.min) / span;
          left = itemCenterX(a.el) + (itemCenterX(b.el) - itemCenterX(a.el)) * t;
          break;
        }
      }
    }

    nowCursorLeft = left;
    nowCursor.style.left = left + 'px';
  }

  function reorderByOra() {
    if (!timeline) return;
    const items = Array.from(timeline.querySelectorAll('.asporto-timeline__item'));
    if (items.length < 2) return;

    items.sort(function (a, b) {
      return String(a.getAttribute('data-ora-ritiro') || '99:99').localeCompare(
        String(b.getAttribute('data-ora-ritiro') || '99:99')
      );
    });

    items.forEach(function (el) {
      timeline.appendChild(el);
    });
  }

  function findFocusItem() {
    if (!timeline) return null;
    const items = Array.from(timeline.querySelectorAll('.asporto-timeline__item'))
      .filter(function (el) { return el.getAttribute('data-stato') !== 'consegnato'; });

    if (!items.length) return null;

    let best = null;
    let bestDiff = Infinity;

    items.forEach(function (el) {
      const info = timingInfo(el.getAttribute('data-ora-ritiro'));
      const diff = info.diffMin != null ? info.diffMin : 9999;
      if (diff < bestDiff) {
        bestDiff = diff;
        best = el;
      }
    });

    return best || items[0];
  }

  function pauseAutoScroll() {
    timelinePausedUntil = Date.now() + USER_PAUSE_MS;
  }

  function scrollToNow(force) {
    if (!timelineScroll || !nowCursor || nowCursor.hidden) {
      scrollToFocus(force);
      return;
    }
    if (!force && Date.now() < timelinePausedUntil) return;

    updateNowCursor();
    const target = Math.max(0, nowCursorLeft - (timelineScroll.clientWidth / 2));
    timelineScroll.scrollTo({ left: target, behavior: 'smooth' });
  }

  function scrollToFocus(force) {
    if (!timelineScroll || !timeline) return;
    if (!force && Date.now() < timelinePausedUntil) return;

    reorderByOra();
    updateNowCursor();

    const focus = findFocusItem();
    timeline.querySelectorAll('.asporto-timeline__item.is-focus').forEach(function (el) {
      el.classList.remove('is-focus');
    });

    if (!focus) {
      scrollToNow(true);
      return;
    }

    focus.classList.add('is-focus');
    const focusCenter = focus.offsetLeft + (focus.offsetWidth / 2);
    const anchor = (!nowCursor || nowCursor.hidden)
      ? focusCenter
      : ((Math.abs(nowCursorLeft - focusCenter) < focus.offsetWidth * 1.5) ? nowCursorLeft : focusCenter);

    timelineScroll.scrollTo({
      left: Math.max(0, anchor - (timelineScroll.clientWidth / 2)),
      behavior: 'smooth'
    });
  }

  function refresh() {
    if (document.hidden) return;
    document.querySelectorAll('[data-timing-target]').forEach(applyTiming);
    updateNowCursor();
    updateTimelineStats();
  }

  function removeItem(id) {
    if (!timeline) return;
    const item = timeline.querySelector('[data-timeline-id="' + id + '"]');
    if (item) item.remove();
    refresh();
  }

  function markConsegnato(id) {
    if (!timeline) return;
    const item = timeline.querySelector('[data-timeline-id="' + id + '"]');
    if (!item) return;
    item.setAttribute('data-stato', 'consegnato');
    item.removeAttribute('data-timing-level');
    item.querySelectorAll('[data-timing-badge]').forEach(function (b) {
      b.textContent = '';
      b.classList.remove('is-visible');
    });
    refresh();
  }

  function reset() {
    timers.forEach(function (id) { clearInterval(id); });
    timers = [];
    if (abort) {
      abort.abort();
      abort = null;
    }
    timelineScroll = null;
    timeline = null;
    btnTimelineNow = null;
    nowCursor = null;
    nowLabel = null;
    timelinePausedUntil = 0;
    nowCursorLeft = 0;
    started = false;
  }

  function init() {
    if (started) reset();

    timelineScroll = document.getElementById('lane-timeline-scroll');
    timeline = document.getElementById('lane-timeline');
    btnTimelineNow = document.getElementById('btn-timeline-now');
    nowCursor = document.getElementById('timeline-now-cursor');
    nowLabel = nowCursor ? nowCursor.querySelector('[data-now-label]') : null;

    if (!timelineScroll || !timeline) return;
    started = true;
    abort = new AbortController();
    const signal = abort.signal;

    ['wheel', 'touchstart', 'pointerdown'].forEach(function (evt) {
      timelineScroll.addEventListener(evt, pauseAutoScroll, { passive: true, signal: signal });
    });

    if (btnTimelineNow) {
      btnTimelineNow.addEventListener('click', function () {
        timelinePausedUntil = 0;
        refresh();
        scrollToNow(true);
      }, { signal: signal });
    }

    refresh();
    scrollToNow(true);
    timers.push(setInterval(refresh, TIMING_REFRESH_MS));
    timers.push(setInterval(function () {
      if (document.hidden) return;
      scrollToFocus(false);
    }, AUTOSCROLL_MS));
    timers.push(setInterval(function () {
      if (document.hidden) return;
      updateNowCursor();
    }, 15000));
  }

  return {
    init: init,
    reset: reset,
    refresh: refresh,
    scrollToNow: scrollToNow,
    scrollToFocus: scrollToFocus,
    removeItem: removeItem,
    markConsegnato: markConsegnato,
    timingInfo: timingInfo,
    applyTiming: applyTiming
  };
})();
</script>
