// Self-Imagining Loop — a dot that accelerates around the loop until the trail
// forms a complete circle. The loop is the smearing of subject/experience/object
// into one continuous "self". Step out to slow it down.
const { useState: useState3, useEffect: useEffect3, useRef: useRef3 } = React;

const loopStyles = {
  wrap: { display: 'grid', gridTemplateColumns: 'minmax(0,1fr) 280px', gap: 36, alignItems: 'stretch' },
  stage: {
    position: 'relative', aspectRatio: '5 / 3',
    background: 'radial-gradient(ellipse at 50% 50%, rgba(207,191,149,0.10), transparent 70%), rgba(38,39,39,0.4)',
    borderRadius: 12, border: '1px solid var(--border)', overflow: 'hidden',
  },
  controls: {
    display: 'flex', flexDirection: 'column', gap: 14,
    padding: 24, background: 'rgba(246,240,226,0.02)',
    border: '1px solid var(--border)', borderRadius: 12,
  },
  caption: {
    fontFamily: 'var(--font-display)', fontSize: 22, lineHeight: 1.1,
    color: 'var(--fg)', letterSpacing: '-0.01em', margin: 0, fontWeight: 600,
  },
  captionSmall: {
    fontFamily: 'var(--font-prose)', fontSize: 13, lineHeight: 1.65,
    color: 'var(--fg-soft)', margin: 0, minHeight: 86,
  },
  legend: {
    display: 'flex', flexDirection: 'column', gap: 8,
    fontFamily: 'var(--font-ui)', fontSize: 11, color: 'var(--fg-soft)',
  },
  legendRow: { display: 'flex', alignItems: 'center', gap: 10, whiteSpace: 'nowrap' },
  legendDot: { width: 8, height: 8, borderRadius: 999 },
  buttonsRow: { display: 'flex', gap: 10, marginTop: 'auto' },
};

const NODES = [
  { id: 'signal', label: 'Signal',
    sub: 'ancient echo',
    angle: -Math.PI / 2 },
  { id: 'story',  label: 'Story',
    sub: 'constructed cause',
    angle: 0 },
  { id: 'self',   label: 'Self',
    sub: 'defended identity',
    angle: Math.PI / 2 },
  { id: 'reinforce', label: 'Reinforce',
    sub: 'filed as evidence',
    angle: Math.PI },
];

// Geometry
const CX = 200, CY = 150, R = 78;
const C  = 2 * Math.PI * R;

// Speed model (cycles per second)
const SPEED_MIN = 0.10; // starts very slow — one revolution per 10s
const SPEED_MAX = 3.50; // fast enough that the trail covers the ring
const RAMP_SEC  = 14;   // time to accelerate to max
const TRAIL_MIN_DEG = 28;
const TRAIL_MAX_DEG = 360;

function easeInOutCubic(t) {
  return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
}

function SelfImaginingLoop() {
  const [stepped, setStepped] = useState3(false);
  const [phaseTitle, setPhaseTitle] = useState3('settling in');
  // phaseTitle: 'settling in' | 'accelerating' | 'the loop' | 'stepped out'

  // refs for rAF-driven values
  const svgRef    = useRef3(null);
  const dotRef    = useRef3(null);
  const dotHaloRef = useRef3(null);
  const trailRef  = useRef3(null);
  const trailGhostRef = useRef3(null);
  const angleRef  = useRef3(-Math.PI / 2);   // start at signal (top)
  const elapsedRef = useRef3(0);             // time accelerating (s)
  const lastTitle  = useRef3('settling in');

  useEffect3(() => {
    let raf;
    let last = performance.now();
    const tick = (now) => {
      const dt = Math.min(0.05, (now - last) / 1000); last = now;

      // ramp elapsed forward when not stepped, decay when stepped
      if (stepped) {
        elapsedRef.current = Math.max(0, elapsedRef.current - dt * 3);
      } else {
        elapsedRef.current = Math.min(RAMP_SEC * 1.4, elapsedRef.current + dt);
      }

      const ramp = Math.min(1, elapsedRef.current / RAMP_SEC);
      const speed = SPEED_MIN + (SPEED_MAX - SPEED_MIN) * easeInOutCubic(ramp);

      // advance angle clockwise — let it grow monotonically (no wrap)
      // so dashoffset never makes a discontinuous jump
      angleRef.current += dt * speed * 2 * Math.PI;

      // trail length grows with speed/ramp, clamped to [0, C] so dash/gap stay positive
      const trailDeg = TRAIL_MIN_DEG + (TRAIL_MAX_DEG - TRAIL_MIN_DEG) * easeInOutCubic(ramp);
      const trailRad = trailDeg * Math.PI / 180;
      const trailUnits = Math.min(C, Math.max(0, (trailRad / (2 * Math.PI)) * C));
      const gapUnits = Math.max(0.001, C - trailUnits);

      // Position of the dot
      const dx = CX + Math.cos(angleRef.current) * R;
      const dy = CY + Math.sin(angleRef.current) * R;

      // Convert angle to circumference position; the SVG circle is rotated -90deg
      // so its natural 0 lines up with our "top" (signal). Our angle uses 0=right.
      // angle relative to top, going clockwise = angle + π/2.
      const angleFromTop = angleRef.current + Math.PI / 2;
      const thetaUnits = (angleFromTop / (2 * Math.PI)) * C;
      const dashOffset = trailUnits - thetaUnits;

      // Apply to DOM
      if (dotRef.current) {
        dotRef.current.setAttribute('cx', dx);
        dotRef.current.setAttribute('cy', dy);
        // dot fades as the trail becomes a solid ring — it's no longer a "thing", it's the loop itself
        dotRef.current.setAttribute('opacity', String(Math.max(0, 1 - ramp * 0.85)));
      }
      if (dotHaloRef.current) {
        dotHaloRef.current.setAttribute('cx', dx);
        dotHaloRef.current.setAttribute('cy', dy);
        dotHaloRef.current.setAttribute('opacity', String(Math.max(0, 1 - ramp * 0.7)));
      }
      if (trailRef.current) {
        trailRef.current.setAttribute('stroke-dasharray', `${trailUnits} ${gapUnits}`);
        trailRef.current.setAttribute('stroke-dashoffset', `${dashOffset}`);
      }
      if (trailGhostRef.current) {
        trailGhostRef.current.setAttribute('stroke-dasharray', `${trailUnits} ${gapUnits}`);
        trailGhostRef.current.setAttribute('stroke-dashoffset', `${dashOffset}`);
      }

      // Phase title (only updated on transition to avoid React thrash)
      let newTitle = 'settling in';
      if (stepped) newTitle = 'stepped out';
      else if (ramp >= 0.92) newTitle = 'the loop';
      else if (ramp >= 0.45) newTitle = 'accelerating';
      if (newTitle !== lastTitle.current) {
        lastTitle.current = newTitle;
        setPhaseTitle(newTitle);
      }

      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [stepped]);

  // pre-compute node screen positions
  const nodePos = NODES.map(n => ({
    ...n,
    x: CX + Math.cos(n.angle) * R,
    y: CY + Math.sin(n.angle) * R,
  }));

  const PANEL = {
    'settling in': {
      caption: 'Signal arises.',
      desc: 'An ancient echo from the body. The mind notices something has happened — a shift, a tightness, a charge.',
    },
    accelerating: {
      caption: 'Story. Self. Reinforce.',
      desc: 'The mind hunts a cause, constructs a story, defends an identity, files the result as evidence. Already the next signal is being shaped.',
    },
    'the loop': {
      caption: 'One continuous "self".',
      desc: 'At this speed, the four elements smear into a single line — the felt sense of being a continuous person. The loop is the self.',
    },
    'stepped out': {
      caption: 'Awareness, without an owner.',
      desc: 'The loop is still running — biology does that. But you are not it. You are what notices.',
    },
  }[phaseTitle];

  return (
    <div style={loopStyles.wrap}>
      <div style={loopStyles.stage}>
        <svg ref={svgRef} viewBox="-50 0 500 300" style={{ position: 'absolute', inset: 0, width: '100%', height: '100%' }}>
          <defs>
            <radialGradient id="loop-center-glow">
              <stop offset="0%" stopColor="rgba(207,191,149,0.35)" />
              <stop offset="60%" stopColor="rgba(207,191,149,0.06)" />
              <stop offset="100%" stopColor="rgba(207,191,149,0)" />
            </radialGradient>
            <radialGradient id="loop-dot-glow">
              <stop offset="0%" stopColor="rgba(207,191,149,0.95)" />
              <stop offset="50%" stopColor="rgba(207,191,149,0.30)" />
              <stop offset="100%" stopColor="rgba(207,191,149,0)" />
            </radialGradient>
            <filter id="loop-blur"><feGaussianBlur stdDeviation="1.2" /></filter>
          </defs>

          {/* THE LOOP */}
          <g style={{ opacity: stepped ? 0.18 : 1, transition: 'opacity 1400ms cubic-bezier(0.4,0,0.2,1)' }}>
            {/* dashed reference ring */}
            <circle cx={CX} cy={CY} r={R} fill="none"
              stroke="rgba(207,191,149,0.18)" strokeWidth="0.8"
              strokeDasharray="2 4" />

            {/* trail — outer glow */}
            <circle ref={trailGhostRef}
              cx={CX} cy={CY} r={R}
              fill="none"
              stroke="rgba(207,191,149,0.35)"
              strokeWidth="6"
              strokeLinecap="round"
              filter="url(#loop-blur)"
              transform={`rotate(-90 ${CX} ${CY})`} />
            {/* trail — bright core */}
            <circle ref={trailRef}
              cx={CX} cy={CY} r={R}
              fill="none"
              stroke="var(--glow)"
              strokeWidth="2.2"
              strokeLinecap="round"
              transform={`rotate(-90 ${CX} ${CY})`} />

            {/* nodes */}
            {nodePos.map(n => (
              <g key={n.id}>
                <circle cx={n.x} cy={n.y} r="11"
                  fill="rgba(38,39,39,0.92)" stroke="rgba(207,191,149,0.35)" strokeWidth="1" />
                <circle cx={n.x} cy={n.y} r="2.5"
                  fill="var(--glow)" opacity="0.7" />
                <text
                  x={n.x + (Math.cos(n.angle) * 28)}
                  y={n.y + (Math.sin(n.angle) * 28) + 4}
                  textAnchor={Math.cos(n.angle) > 0.5 ? 'start' : (Math.cos(n.angle) < -0.5 ? 'end' : 'middle')}
                  fontFamily="var(--font-display)"
                  fontSize="16" fontWeight="600"
                  fill="var(--fg)"
                  style={{ textTransform: 'lowercase', letterSpacing: '-0.01em' }}>
                  {n.label}
                </text>
                <text
                  x={n.x + (Math.cos(n.angle) * 28)}
                  y={n.y + (Math.sin(n.angle) * 28) + 17}
                  textAnchor={Math.cos(n.angle) > 0.5 ? 'start' : (Math.cos(n.angle) < -0.5 ? 'end' : 'middle')}
                  fontFamily="var(--font-ui)" fontSize="8"
                  letterSpacing="0.18em" style={{ textTransform: 'uppercase' }}
                  fill="var(--muted)">
                  {n.sub}
                </text>
              </g>
            ))}

            {/* dot — head of the comet */}
            <circle ref={dotHaloRef} cx={CX} cy={CY - R} r="14" fill="url(#loop-dot-glow)" />
            <circle ref={dotRef}     cx={CX} cy={CY - R} r="3.5" fill="var(--glow)" />
          </g>

          {/* WITNESS — visible when stepped */}
          <g style={{ opacity: stepped ? 1 : 0.0, transition: 'opacity 1600ms cubic-bezier(0.4,0,0.2,1)' }}>
            <circle cx={CX} cy={CY} r="90" fill="url(#loop-center-glow)" />
            <circle cx={CX} cy={CY} r="2.5" fill="var(--glow)" />
            <text x={CX} y={CY + 4} textAnchor="middle"
              fontFamily="var(--font-display)" fontSize="20" fontWeight="500"
              fill="var(--glow)" fontStyle="italic"
              style={{ letterSpacing: '-0.01em' }}>
              what notices
            </text>
            <text x={CX} y={CY + 26} textAnchor="middle"
              fontFamily="var(--font-ui)" fontSize="8"
              fill="var(--muted)" letterSpacing="0.32em"
              style={{ textTransform: 'uppercase' }}>
              not in the loop
            </text>
          </g>
        </svg>

        <div style={{
          position: 'absolute', top: 14, left: 16,
          fontFamily: 'var(--font-ui)', fontSize: 9, letterSpacing: '0.32em',
          textTransform: 'uppercase', color: 'var(--muted)',
        }}>
          self-imagining loop
        </div>
        <div style={{
          position: 'absolute', bottom: 14, left: 16,
          fontFamily: 'var(--font-ui)', fontSize: 9, letterSpacing: '0.32em',
          textTransform: 'uppercase', color: 'var(--glow)',
          transition: 'color 800ms cubic-bezier(0.4,0,0.2,1)',
        }}>
          {phaseTitle}
        </div>
      </div>

      <div style={loopStyles.controls}>
        <h4 style={loopStyles.caption}>{PANEL.caption}</h4>
        <p style={loopStyles.captionSmall}>{PANEL.desc}</p>

        <div style={loopStyles.legend}>
          {NODES.map(n => (
            <div key={n.id} style={loopStyles.legendRow}>
              <span style={{
                ...loopStyles.legendDot,
                background: 'rgba(207,191,149,0.5)',
              }}></span>
              <span>{n.label.toLowerCase()} — <span style={{ color: 'var(--muted)' }}>{n.sub}</span></span>
            </div>
          ))}
        </div>

        <div style={loopStyles.buttonsRow}>
          {!stepped ? (
            <button className="luma-button luma-button--primary" style={{ flex: 1 }}
              onClick={() => setStepped(true)}>
              step out
            </button>
          ) : (
            <button className="luma-button" style={{ flex: 1 }}
              onClick={() => setStepped(false)}>
              re-enter
            </button>
          )}
        </div>
      </div>
    </div>
  );
}

window.SelfImaginingLoop = SelfImaginingLoop;
