// Cycle preview — interactive wheel with idle rotation, drag-to-rotate,
// auto-play on first view, and active phase detail.
const { useState: useStateCP, useEffect: useEffectCP, useRef: useRefCP, useCallback: useCallbackCP } = React;

const CYCLE_PHASES = [
  { key: 'assess',    label: 'Assess',    num: '01', summary: 'Full audit of your stack, workflows, and spend. Ranked roadmap by ROI.', timing: '1–2 weeks' },
  { key: 'implement', label: 'Implement', num: '02', summary: 'Build & deploy top-ROI systems first. Security from day one.',             timing: 'First systems in 30–60 days' },
  { key: 'optimize',  label: 'Optimize',  num: '03', summary: 'Measure everything. Fine-tune on real data, not assumptions.',              timing: 'Monthly cycles' },
  { key: 'scale',     label: 'Scale',     num: '04', summary: 'Expand what works. Build internal capability over time.',                   timing: 'Quarterly sprints' },
];

window.CyclePreview = function CyclePreview() {
  const [active, setActive] = useStateCP(0);
  const [rot, setRot] = useStateCP(0);                    // radians, continuous idle spin
  const [phaseDeg, setPhaseDeg] = useStateCP(0);          // continuous degrees, tracks active phase rotation
  const [dragging, setDragging] = useStateCP(false);
  const [hovering, setHovering] = useStateCP(false);
  const [autoplayed, setAutoplayed] = useStateCP(false);
  const [showHint, setShowHint] = useStateCP(false);
  const svgRef = useRefCP(null);
  const wheelRef = useRefCP(null);
  const dragStart = useRefCP({ angle: 0, rot: 0 });
  const lastT = useRefCP(performance.now());
  const visibleRef = useRefCP(false);

  // When the active phase changes, rotate the wheel via the SHORTEST
  // angular path to put the active phase at the top. Previous version
  // always added +90° per phase, so jumping 01 → 04 meant spinning +270°
  // ("blowing up and reassembling"). Clamping to [-180, 180] deltas
  // keeps every transition a calm ≤90° rotation in the obvious direction.
  useEffectCP(() => {
    const target = active * 90;
    const current = ((phaseDeg % 360) + 360) % 360;
    let delta = target - current;
    if (delta > 180) delta -= 360;
    if (delta < -180) delta += 360;
    setPhaseDeg(phaseDeg + delta);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [active]);

  // Idle rotation loop (~1 turn / 240s — very slow, ambient motion, almost
  // subliminal). Pauses on hover/drag.
  useEffectCP(() => {
    let raf;
    const tick = (t) => {
      const dt = (t - lastT.current) / 1000;
      lastT.current = t;
      if (!hovering && !dragging && visibleRef.current) {
        setRot(r => r + dt * (Math.PI * 2) / 240);
      }
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [hovering, dragging]);

  // Auto-play the phase cycle once on first view, then hand control to the user.
  // Interval widened from 900ms to 1800ms so the wheel breathes between phase
  // transitions instead of jump-cutting. Transition easing is 1.2s (see the
  // rotating <g> below) so each phase has a full, calm beat before the next.
  useEffectCP(() => {
    if (!wheelRef.current) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => {
        visibleRef.current = e.isIntersecting;
        if (e.isIntersecting && !autoplayed) {
          setAutoplayed(true);
          let i = 0;
          const step = () => {
            setActive(i % CYCLE_PHASES.length);
            i++;
            if (i <= CYCLE_PHASES.length) setTimeout(step, 2500);
            else setTimeout(() => setShowHint(true), 800);
          };
          step();
          setTimeout(() => setShowHint(false), 10000);
        }
      });
    }, { threshold: 0.3 });
    io.observe(wheelRef.current);
    return () => io.disconnect();
  }, [autoplayed]);

  // Drag-to-rotate handlers.
  const getAngle = (e) => {
    const svg = svgRef.current;
    if (!svg) return 0;
    const rect = svg.getBoundingClientRect();
    const cx = rect.left + rect.width / 2;
    const cy = rect.top + rect.height / 2;
    const p = e.touches ? e.touches[0] : e;
    return Math.atan2(p.clientY - cy, p.clientX - cx);
  };
  const onDown = (e) => {
    setDragging(true);
    dragStart.current = { angle: getAngle(e), rot };
    e.preventDefault();
  };
  const onMove = useCallbackCP((e) => {
    if (!dragging) return;
    const a = getAngle(e);
    const delta = a - dragStart.current.angle;
    setRot(dragStart.current.rot + delta);
  }, [dragging]);
  const onUp = useCallbackCP(() => setDragging(false), []);

  useEffectCP(() => {
    if (!dragging) return;
    window.addEventListener('mousemove', onMove);
    window.addEventListener('mouseup', onUp);
    window.addEventListener('touchmove', onMove, { passive: false });
    window.addEventListener('touchend', onUp);
    return () => {
      window.removeEventListener('mousemove', onMove);
      window.removeEventListener('mouseup', onUp);
      window.removeEventListener('touchmove', onMove);
      window.removeEventListener('touchend', onUp);
    };
  }, [dragging, onMove, onUp]);

  const R = 140;
  const cx = 180, cy = 180;

  return (
    <section className="cycle-section" data-section-nav="The Cycle">
      <div className="container">
        <div className="section-head left" style={{ marginBottom: 72 }}>
          <span className="kicker">Our Methodology</span>
          <h2 style={{ marginTop: 20 }}>The Technology Cycle.</h2>
          <p style={{ maxWidth: 620 }}>
            A continuous improvement framework. Not one-and-done — how we operate, and why results compound quarter over quarter.
          </p>
        </div>

        <div className="cycle-layout">
          <div className="cycle-wheel-wrap" ref={wheelRef}>
            <svg
              ref={svgRef}
              viewBox="0 0 360 360"
              className={`cycle-wheel ${dragging ? 'dragging' : ''}`}
              role="img"
              aria-label="Four-phase Technology Cycle diagram — drag to rotate"
              onMouseEnter={() => setHovering(true)}
              onMouseLeave={() => setHovering(false)}
              onMouseDown={onDown}
              onTouchStart={onDown}
            >
              <defs>
                <linearGradient id="cycle-ring" x1="0" y1="0" x2="1" y2="1">
                  <stop offset="0%" stopColor="#5BC5E3" />
                  <stop offset="50%" stopColor="#6B8BC5" />
                  <stop offset="100%" stopColor="#7B5DAD" />
                </linearGradient>
              </defs>

              {/* outer ring */}
              <circle cx={cx} cy={cy} r={R} fill="none" stroke="var(--border)" strokeWidth="1" />
              <circle cx={cx} cy={cy} r={R - 24} fill="none" stroke="var(--border)" strokeWidth="1" strokeDasharray="2 4" />

              {/* Ambient rotating group — idle spin + active-phase
                  rotation. `phaseDeg` is updated via shortest-path
                  whenever active changes, so 01 → 04 rotates -90°
                  instead of +270°. Transition smooths over 1.8s. */}
              <g
                transform={`rotate(${rot * 180 / Math.PI + phaseDeg} ${cx} ${cy})`}
                style={{ transition: dragging ? 'none' : 'transform 1.8s var(--ease-out)' }}
              >
                {/* Full ring — a continuous colored circle so the four
                    phases visually connect (was a 1/4 arc that only
                    showed the segment between the previous and current
                    phase). */}
                <circle
                  cx={cx} cy={cy} r={R}
                  fill="none"
                  stroke="url(#cycle-ring)"
                  strokeWidth="2"
                  strokeLinecap="round"
                  opacity="0.85"
                />
                {/* phase nodes */}
                {CYCLE_PHASES.map((p, i) => {
                  const angle = (i * Math.PI * 2) / CYCLE_PHASES.length - Math.PI / 2;
                  const x = cx + Math.cos(angle) * R;
                  const y = cy + Math.sin(angle) * R;
                  const isActive = i === active;
                  // The outer <g> rotates the nodes around the wheel. To keep
                  // each number reading upright instead of flipping upside
                  // down, we wrap the <text> in an inner group that applies
                  // the INVERSE rotation about the node's own position —
                  // cancelling the parent rotation precisely at this point.
                  // Must match parent rotation exactly: idle (rot) + shortest-
                  // path phase rotation (phaseDeg).
                  const parentRotDeg = (rot * 180 / Math.PI) + phaseDeg;
                  return (
                    <g key={p.key} onClick={(e) => { e.stopPropagation(); setActive(i); }} style={{ cursor: 'pointer' }}>
                      <circle cx={x} cy={y} r={isActive ? 20 : 12} fill={isActive ? 'url(#cycle-ring)' : 'var(--bg-elevated)'} stroke={isActive ? 'transparent' : 'var(--border-strong)'} strokeWidth="1.5" style={{ transition: 'all 0.4s var(--ease-out)' }} />
                      <g transform={`rotate(${-parentRotDeg} ${x} ${y})`} style={{ transition: dragging ? 'none' : 'transform 1.8s var(--ease-out)' }}>
                        <text x={x} y={y + 4} textAnchor="middle" fontSize="11" fontFamily="var(--font-mono)" fill={isActive ? '#fff' : 'var(--text-dim)'} style={{ transition: 'fill 0.3s', userSelect: 'none' }}>{p.num}</text>
                      </g>
                    </g>
                  );
                })}
              </g>

              {/* center label — counter-rotation so it always reads upright */}
              <text x={cx} y={cy - 6} textAnchor="middle" fontSize="11" fontFamily="var(--font-mono)" fill="var(--text-dim)" letterSpacing="2">PHASE</text>
              <text x={cx} y={cy + 24} textAnchor="middle" fontSize="32" fontFamily="var(--font-display)" fontWeight="500" fill="var(--text)" letterSpacing="-1">{CYCLE_PHASES[active].num}</text>
            </svg>
            {/* drag hint removed — wheel affords rotation on hover/grab */}
          </div>

          <div className="cycle-detail">
            {CYCLE_PHASES.map((p, i) => (
              <button
                key={p.key}
                className={`cycle-item ${i === active ? 'active' : ''}`}
                onClick={() => setActive(i)}
              >
                <span className="cycle-item-num mono">{p.num}</span>
                <div className="cycle-item-body">
                  <div className="cycle-item-title">
                    <span>{p.label}</span>
                    <span className="cycle-item-time mono">{p.timing}</span>
                  </div>
                  <p>{p.summary}</p>
                </div>
              </button>
            ))}
            {/* Hide this link when we're already on the-cycle page —
                otherwise it circles back to the same place. On /the-cycle
                we swap it for a jump-to-phases anchor so the affordance
                still works. */}
            {typeof window !== 'undefined' && /the-cycle/.test(window.location.pathname) ? (
              <a href="#phases" className="cycle-link"
                 onClick={(e) => {
                   const el = document.querySelector('.cycle-full-detail');
                   if (el) { e.preventDefault(); el.scrollIntoView({ behavior: 'smooth', block: 'start' }); }
                 }}>
                See each phase in detail <span>↓</span>
              </a>
            ) : (
              <a href="the-cycle.html" className="cycle-link">
                Explore the full methodology <span>→</span>
              </a>
            )}
          </div>
        </div>
      </div>
    </section>
  );
};
