/* Krytz · Workflow timeline scrubber
 *
 * 24-hour timeline. Drag the handle to scrub through a day; events
 * (captures, decisions, rank changes, blockers, completions) tick
 * by with past/current/future opacity. Optional play mode auto-
 * advances time.
 */

(function () {
  const { useState, useEffect, useRef, useMemo, useCallback } = React;

  /* A representative day. Time is minutes from 00:00. */
  const EVENTS = [
    { t: 8 * 60 + 12, type: 'capture',   title: 'Morning brain-dump',         sub: 'voice · 38s · 6 items extracted' },
    { t: 8 * 60 + 14, type: 'decision',  title: 'Primary set: "Fix staging bug"', sub: 'urgency 0.92 · deps 0.88' },
    { t: 9 * 60 + 5,  type: 'capture',   title: 'Slack thread captured',      sub: 'paste · 1.2k chars · 3 items' },
    { t: 9 * 60 + 24, type: 'rank',      title: 'Asha proposal moved #4 → #2', sub: 'mention bump + deadline drift' },
    { t: 10 * 60 + 2, type: 'complete',  title: 'Fix staging bug',            sub: 'done in 1h 48m' },
    { t: 10 * 60 + 8, type: 'rank',      title: 'QA sign-off promoted to primary', sub: 'unblocked by previous' },
    { t: 10 * 60 + 41, type: 'capture',  title: '1:1 notes captured',         sub: 'typed · 320 chars · 4 items' },
    { t: 11 * 60 + 3, type: 'blocker',   title: 'Pricing review · owner unclear', sub: 'awaiting clarification' },
    { t: 11 * 60 + 50, type: 'decision', title: 'Snoozed "Update API docs" → tomorrow', sub: 'capacity at 92%' },
    { t: 12 * 60 + 35, type: 'capture',  title: 'Hallway voice memo',         sub: 'voice · 22s · 2 items' },
    { t: 13 * 60 + 18, type: 'complete', title: 'QA sign-off for v2.3',       sub: 'done in 2h 14m' },
    { t: 13 * 60 + 22, type: 'rank',     title: 'Prod rollout promoted',      sub: 'all blockers cleared' },
    { t: 14 * 60 + 5,  type: 'decision', title: 'Deferred Q3 metrics → Friday', sub: 'simulation: −18 pressure' },
    { t: 14 * 60 + 44, type: 'capture',  title: 'Email forwarded · Asha reply', sub: 'inbox · 1 item' },
    { t: 15 * 60 + 12, type: 'rank',     title: 'Asha proposal moved #2 → #1', sub: 'response received · urgency +' },
    { t: 16 * 60 + 8,  type: 'capture',  title: 'Board sync notes',           sub: 'typed · 5 items extracted' },
    { t: 16 * 60 + 30, type: 'blocker',  title: 'Investor deck waiting on data', sub: 'blocked by metrics review' },
    { t: 17 * 60 + 11, type: 'complete', title: 'Send Asha proposal v3',      sub: 'done · 18m before deadline' },
    { t: 17 * 60 + 42, type: 'decision', title: 'Tomorrow primary: investor deck', sub: 'pre-decided · scheduled' },
    { t: 18 * 60 + 4,  type: 'capture',  title: 'End-of-day shutdown ritual', sub: 'voice · 12s · 1 reflection' },
  ];

  const DAY = 24 * 60;
  const VISIBLE_RADIUS = 90; // minutes shown around the cursor
  const ROW_PX = 56;

  function fmtTime(min) {
    const h = Math.floor(min / 60);
    const m = Math.floor(min % 60);
    const ap = h >= 12 ? 'PM' : 'AM';
    const hh = h % 12 || 12;
    const mm = m.toString().padStart(2, '0');
    return { hh, mm, ap };
  }

  function TimelineScrubber() {
    const trackRef = useRef(null);
    const [now, setNow] = useState(11 * 60); // start at 11:00 AM
    const [playing, setPlaying] = useState(false);
    const [speed, setSpeed] = useState(8);
    const draggingRef = useRef(false);

    /* Stats up to "now" */
    const stats = useMemo(() => {
      const past = EVENTS.filter((e) => e.t <= now);
      const captures = past.filter((e) => e.type === 'capture').length;
      const decisions = past.filter((e) => e.type === 'decision' || e.type === 'rank').length;
      const completed = past.filter((e) => e.type === 'complete').length;
      return { captures, decisions, completed };
    }, [now]);

    /* Play loop */
    useEffect(() => {
      if (!playing) return;
      let raf;
      let last = performance.now();
      const step = (t) => {
        const dt = (t - last) / 1000;
        last = t;
        setNow((n) => {
          const next = n + dt * speed;
          if (next >= DAY) {
            setPlaying(false);
            return DAY;
          }
          return next;
        });
        raf = requestAnimationFrame(step);
      };
      raf = requestAnimationFrame(step);
      return () => cancelAnimationFrame(raf);
    }, [playing, speed]);

    /* Scrubber drag */
    const moveTo = useCallback((clientX) => {
      const rect = trackRef.current.getBoundingClientRect();
      const k = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
      setNow(k * DAY);
    }, []);

    const onPointerDown = (e) => {
      draggingRef.current = true;
      e.currentTarget.setPointerCapture(e.pointerId);
      moveTo(e.clientX);
    };
    const onPointerMove = (e) => {
      if (!draggingRef.current) return;
      moveTo(e.clientX);
    };
    const onPointerUp = (e) => {
      draggingRef.current = false;
    };

    const pct = (now / DAY) * 100;

    /* Position events near cursor — pin past above, future below */
    const eventsWithPos = useMemo(() => {
      return EVENTS.map((e) => {
        const dt = e.t - now;
        const phase = dt < -2 ? 'past' : (dt > 2 ? 'future' : 'current');
        // y in px from center
        const y = (dt / VISIBLE_RADIUS) * 90; // 90px per VISIBLE_RADIUS
        // visible if within window
        const visible = Math.abs(dt) <= VISIBLE_RADIUS * 1.4;
        return { ...e, phase, y, visible };
      });
    }, [now]);

    const { hh, mm, ap } = fmtTime(now);

    return (
      <div className="tl-wrap">
        <div className="tl-head">
          <div>
            <div className="tl-time">
              {hh}:{mm}<span className="ampm">{ap}</span>
            </div>
            <div className="tl-day">Wed · May 14 · 2026</div>
          </div>
          <div className="tl-stats">
            <div className="tl-stat">
              <div className="v">{stats.captures}</div>
              <div className="l">Captures</div>
            </div>
            <div className="tl-stat">
              <div className="v">{stats.decisions}</div>
              <div className="l">Decisions</div>
            </div>
            <div className="tl-stat">
              <div className="v">{stats.completed}</div>
              <div className="l">Completed</div>
            </div>
          </div>
        </div>

        <div
          className="tl-scrubber-wrap"
          ref={trackRef}
          onPointerDown={onPointerDown}
          onPointerMove={onPointerMove}
          onPointerUp={onPointerUp}
          onPointerCancel={onPointerUp}
        >
          <div className="tl-track" />
          <div className="tl-fill" style={{ width: `${pct}%` }} />
          <div className="tl-handle" style={{ left: `${pct}%` }} />
          <div className="tl-ticks">
            {Array.from({ length: 9 }).map((_, i) => {
              const hour = i * 3;
              return (
                <div key={i} className={`tl-tick ${i % 2 === 0 ? 'major' : ''}`}>
                  <div className="bar" />
                  <div className="lbl">{hour.toString().padStart(2, '0')}:00</div>
                </div>
              );
            })}
          </div>
        </div>

        <div className="tl-events">
          <div className="tl-cursor-line" style={{ left: '50%' }} />
          <div className="tl-events-inner">
            {eventsWithPos.map((e, i) => {
              if (!e.visible) return null;
              // center y is ~50% of the height
              const centerY = 110;
              return (
                <div
                  key={i}
                  className={`tl-event ${e.type} is-${e.phase}`}
                  style={{
                    transform: `translateY(${centerY + e.y - 18}px)`,
                  }}
                >
                  <span className="t">{fmtTime(e.t).hh.toString().padStart(2,'0')}:{fmtTime(e.t).mm}</span>
                  <span className="type">{e.type}</span>
                  <span className="txt">
                    {e.title}
                    {e.sub && <><br/><span className="sub">{e.sub}</span></>}
                  </span>
                </div>
              );
            })}
          </div>
        </div>

        <div className="tl-controls">
          <button className="tl-play" onClick={() => setPlaying((p) => !p)} aria-label={playing ? 'Pause' : 'Play'}>
            {playing
              ? <svg width="12" height="14" viewBox="0 0 12 14" fill="currentColor"><rect x="1" y="1" width="3.5" height="12"/><rect x="7.5" y="1" width="3.5" height="12"/></svg>
              : <svg width="12" height="14" viewBox="0 0 12 14" fill="currentColor"><path d="M1 1 L11 7 L1 13 Z"/></svg>
            }
          </button>
          <div className="tl-speed">
            Speed
            <select value={speed} onChange={(e) => setSpeed(parseInt(e.target.value, 10))}>
              <option value="2">2× (slow)</option>
              <option value="8">8× (auto)</option>
              <option value="30">30× (fast)</option>
              <option value="120">120× (sweep)</option>
            </select>
          </div>
          <div style={{ marginLeft: 'auto', fontFamily: 'var(--mono)', fontSize: 11, color: 'var(--ink-3)', letterSpacing: '0.06em' }}>
            {EVENTS.length} events · drag handle or press play
          </div>
        </div>
      </div>
    );
  }

  window.TimelineScrubber = TimelineScrubber;
})();
