// Pipeline: the interactive centerpiece.
// Features: animated flow, draggable bottleneck, clickable stages, metaphor variants.

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

// ---------- Shared hook: spring animation ----------
function useSpring(target, { stiffness = 120, damping = 18 } = {}) {
  const [value, setValue] = useState(target);
  const vRef = useRef(target);
  const velRef = useRef(0);
  const rafRef = useRef(null);
  const lastRef = useRef(performance.now());

  useEffect(() => {
    const tick = (now) => {
      const dt = Math.min(0.033, (now - lastRef.current) / 1000);
      lastRef.current = now;
      const diff = target - vRef.current;
      const accel = stiffness * diff - damping * velRef.current;
      velRef.current += accel * dt;
      vRef.current += velRef.current * dt;
      if (Math.abs(diff) < 0.0005 && Math.abs(velRef.current) < 0.0005) {
        vRef.current = target;
        velRef.current = 0;
        setValue(target);
        return;
      }
      setValue(vRef.current);
      rafRef.current = requestAnimationFrame(tick);
    };
    lastRef.current = performance.now();
    rafRef.current = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(rafRef.current);
  }, [target, stiffness, damping]);

  return value;
}

// ---------- Flowing particles along the pipeline ----------
function FlowingParticles({ width, count = 7, bottleneckX = null, severity = 0, method = false }) {
  const [t, setT] = useState(0);
  useEffect(() => {
    let raf;
    const start = performance.now();
    const tick = (now) => {
      setT((now - start) / 1000);
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, []);

  const dots = [];
  for (let i = 0; i < count; i++) {
    const phase = (i / count) + t * (method ? 0.18 : 0.13);
    let p = phase % 1;
    // Bottleneck slowdown / pileup
    if (bottleneckX !== null && !method) {
      const bX = bottleneckX / width;
      const dist = p - bX;
      // slow down before the bottleneck
      if (dist > -0.12 && dist < 0) {
        const slow = 1 - (0.12 + dist) / 0.12;
        p = bX + (dist * (1 - severity * 0.6 * slow));
      }
    }
    const x = p * width;
    const opacity = method ? 0.9 : (bottleneckX !== null && Math.abs(x - bottleneckX) < 40 ? 0.4 : 0.85);
    dots.push(
      <circle
        key={i}
        cx={x}
        cy={0}
        r={method ? 3.5 : 3}
        fill={method ? "var(--flow-good)" : "var(--ink)"}
        opacity={opacity}
      />
    );
  }
  return <g>{dots}</g>;
}

// ---------- Pipeline (flow metaphor) ----------
function PipelineFlow({
  bottleneckIdx,
  onBottleneckChange,
  activeStage,
  onStageClick,
  method,
  draggable = true,
}) {
  const W = 1100;
  const H = 280;
  const pad = 60;
  const trackY = 160;
  const stepW = (W - pad * 2) / (STAGES.length - 1);

  const stageX = (i) => pad + i * stepW;
  const bottleneckX = bottleneckIdx !== null && bottleneckIdx !== undefined
    ? stageX(bottleneckIdx)
    : null;

  const svgRef = useRef(null);
  const [dragging, setDragging] = useState(false);

  const handlePointer = useCallback(
    (clientX) => {
      if (!svgRef.current) return;
      const rect = svgRef.current.getBoundingClientRect();
      const xInSvg = ((clientX - rect.left) / rect.width) * W;
      // snap to nearest stage
      const ratio = (xInSvg - pad) / stepW;
      const idx = Math.max(0, Math.min(STAGES.length - 1, Math.round(ratio)));
      onBottleneckChange(idx);
    },
    [onBottleneckChange]
  );

  useEffect(() => {
    if (!dragging) return;
    const move = (e) => {
      const clientX = e.touches ? e.touches[0].clientX : e.clientX;
      handlePointer(clientX);
    };
    const up = () => setDragging(false);
    window.addEventListener("mousemove", move);
    window.addEventListener("mouseup", up);
    window.addEventListener("touchmove", move);
    window.addEventListener("touchend", up);
    return () => {
      window.removeEventListener("mousemove", move);
      window.removeEventListener("mouseup", up);
      window.removeEventListener("touchmove", move);
      window.removeEventListener("touchend", up);
    };
  }, [dragging, handlePointer]);

  const markerX = useSpring(bottleneckX ?? pad, { stiffness: 200, damping: 22 });

  return (
    <svg
      ref={svgRef}
      viewBox={`0 0 ${W} ${H}`}
      className="pipeline-svg"
      style={{ width: "100%", height: "auto", userSelect: "none", touchAction: "none" }}
    >
      {/* Track */}
      <line
        x1={pad}
        y1={trackY}
        x2={W - pad}
        y2={trackY}
        stroke="var(--ink-dim)"
        strokeWidth="1.5"
      />
      {/* Track (healthy glow if method) */}
      {method && (
        <line
          x1={pad}
          y1={trackY}
          x2={W - pad}
          y2={trackY}
          stroke="var(--flow-good)"
          strokeWidth="4"
          strokeLinecap="round"
          opacity="0.25"
        />
      )}

      {/* Flowing particles */}
      <g transform={`translate(0, ${trackY})`}>
        <FlowingParticles
          width={W - pad * 2}
          count={method ? 9 : 7}
          bottleneckX={!method ? (bottleneckX ? bottleneckX - pad : null) : null}
          severity={1}
          method={method}
        />
        <g transform={`translate(${pad}, 0)`} />
      </g>

      {/* Stages */}
      {STAGES.map((s, i) => {
        const x = stageX(i);
        const isBottleneck = i === bottleneckIdx && !method;
        const isActive = activeStage === s.id;
        return (
          <g
            key={s.id}
            transform={`translate(${x}, ${trackY})`}
            style={{ cursor: "pointer" }}
            onClick={() => onStageClick?.(s.id)}
          >
            <circle
              r={isActive ? 12 : 8}
              fill={method ? "var(--flow-good)" : (isBottleneck ? "var(--accent)" : "var(--bg)")}
              stroke={isBottleneck ? "var(--accent)" : (method ? "var(--flow-good)" : "var(--ink)")}
              strokeWidth="1.75"
              style={{ transition: "r 260ms cubic-bezier(.2,.8,.2,1)" }}
            />
            {isBottleneck && (
              <circle r="18" fill="var(--accent)" opacity="0.18">
                <animate attributeName="r" values="14;24;14" dur="2s" repeatCount="indefinite" />
                <animate attributeName="opacity" values="0.25;0.05;0.25" dur="2s" repeatCount="indefinite" />
              </circle>
            )}
            <text
              y={-24}
              textAnchor="middle"
              className="stage-label"
              fill={isActive || isBottleneck ? "var(--ink)" : "var(--ink-dim)"}
              style={{ fontWeight: isActive || isBottleneck ? 600 : 500 }}
            >
              {s.label}
            </text>
          </g>
        );
      })}

      {/* Draggable bottleneck marker */}
      {draggable && bottleneckIdx !== null && !method && (
        <g transform={`translate(${markerX}, ${trackY + 56})`}>
          <g
            onMouseDown={(e) => {
              e.preventDefault();
              setDragging(true);
            }}
            onTouchStart={(e) => {
              e.preventDefault();
              setDragging(true);
            }}
            style={{ cursor: dragging ? "grabbing" : "grab" }}
          >
            <rect
              x={-62}
              y={-18}
              width={124}
              height={30}
              rx={15}
              fill="var(--ink)"
            />
            <text
              y={2}
              textAnchor="middle"
              fill="var(--bg)"
              style={{ fontSize: 12, fontWeight: 600, letterSpacing: "0.02em" }}
            >
              ⇠ Bottleneck ⇢
            </text>
          </g>
          {/* tether */}
          <line x1={0} y1={-18} x2={0} y2={-40} stroke="var(--ink)" strokeWidth="1.25" />
        </g>
      )}

      {/* Feedback loops */}
      <path
        d={`M ${stageX(4)} ${trackY - 6} Q ${stageX(3.3)} ${trackY - 60}, ${stageX(3)} ${trackY - 6}`}
        fill="none"
        stroke="var(--ink-dim)"
        strokeWidth="1"
        strokeDasharray="3 3"
      />
      <path
        d={`M ${stageX(6)} ${trackY - 6} Q ${stageX(3.5)} ${trackY - 110}, ${stageX(1)} ${trackY - 6}`}
        fill="none"
        stroke="var(--ink-dim)"
        strokeWidth="1"
        strokeDasharray="3 3"
      />
    </svg>
  );
}

// ---------- Pipeline (circuit metaphor) ----------
function PipelineCircuit({ bottleneckIdx, onStageClick, activeStage, method }) {
  const W = 1100;
  const H = 280;
  const pad = 60;
  const trackY = 160;
  const stepW = (W - pad * 2) / (STAGES.length - 1);
  const stageX = (i) => pad + i * stepW;

  return (
    <svg viewBox={`0 0 ${W} ${H}`} style={{ width: "100%", height: "auto" }}>
      {/* rail top + bottom */}
      <line x1={pad} y1={trackY - 14} x2={W - pad} y2={trackY - 14} stroke="var(--ink)" strokeWidth="1" />
      <line x1={pad} y1={trackY + 14} x2={W - pad} y2={trackY + 14} stroke="var(--ink)" strokeWidth="1" />
      {STAGES.map((s, i) => {
        const x = stageX(i);
        const isBottleneck = i === bottleneckIdx && !method;
        const isActive = activeStage === s.id;
        return (
          <g key={s.id} transform={`translate(${x}, ${trackY})`} style={{ cursor: "pointer" }} onClick={() => onStageClick?.(s.id)}>
            {/* valve */}
            <rect
              x={-12} y={-22} width={24} height={44} rx={3}
              fill={method ? "var(--flow-good)" : (isBottleneck ? "var(--accent)" : "var(--bg)")}
              stroke={isBottleneck ? "var(--accent)" : "var(--ink)"}
              strokeWidth="1.25"
            />
            <line x1={-6} y1={0} x2={6} y2={0} stroke={isBottleneck || method ? "var(--bg)" : "var(--ink)"} strokeWidth="1.25" />
            <text y={-34} textAnchor="middle" className="stage-label" fill={isActive || isBottleneck ? "var(--ink)" : "var(--ink-dim)"} style={{ fontWeight: isActive || isBottleneck ? 600 : 500 }}>
              {s.label}
            </text>
            {isBottleneck && (
              <circle r="26" fill="var(--accent)" opacity="0.15">
                <animate attributeName="r" values="22;32;22" dur="2s" repeatCount="indefinite" />
              </circle>
            )}
          </g>
        );
      })}
    </svg>
  );
}

// ---------- Pipeline (stack metaphor) ----------
function PipelineStack({ bottleneckIdx, onStageClick, activeStage, method }) {
  const W = 1100;
  const rowH = 34;
  const H = rowH * STAGES.length + 40;

  return (
    <svg viewBox={`0 0 ${W} ${H}`} style={{ width: "100%", height: "auto" }}>
      {STAGES.map((s, i) => {
        const y = 20 + i * rowH;
        const isBottleneck = i === bottleneckIdx && !method;
        const isActive = activeStage === s.id;
        return (
          <g key={s.id} transform={`translate(0, ${y})`} style={{ cursor: "pointer" }} onClick={() => onStageClick?.(s.id)}>
            <rect
              x={60}
              y={2}
              width={W - 120}
              height={rowH - 6}
              rx={4}
              fill={method ? "var(--flow-good-soft)" : (isBottleneck ? "var(--accent-soft)" : "transparent")}
              stroke={isBottleneck ? "var(--accent)" : (method ? "var(--flow-good)" : "var(--ink-dim)")}
              strokeWidth="1"
            />
            <text x={80} y={rowH / 2 + 5} className="stage-label" fill="var(--ink)" style={{ fontWeight: isActive || isBottleneck ? 600 : 500 }}>
              {String(i + 1).padStart(2, "0")} · {s.label}
            </text>
            <text x={W - 80} y={rowH / 2 + 5} textAnchor="end" style={{ fontSize: 11, fill: "var(--ink-dim)", fontFamily: "var(--mono)" }}>
              {s.produces}
            </text>
          </g>
        );
      })}
    </svg>
  );
}

// ---------- Main exported Pipeline ----------
function Pipeline({
  bottleneckIdx,
  onBottleneckChange,
  activeStage,
  onStageClick,
  metaphor = "flow",
  method = false,
  draggable = true,
}) {
  if (metaphor === "circuit")
    return <PipelineCircuit bottleneckIdx={bottleneckIdx} onStageClick={onStageClick} activeStage={activeStage} method={method} />;
  if (metaphor === "stack")
    return <PipelineStack bottleneckIdx={bottleneckIdx} onStageClick={onStageClick} activeStage={activeStage} method={method} />;
  return (
    <PipelineFlow
      bottleneckIdx={bottleneckIdx}
      onBottleneckChange={onBottleneckChange}
      activeStage={activeStage}
      onStageClick={onStageClick}
      method={method}
      draggable={draggable}
    />
  );
}

Object.assign(window, { Pipeline, useSpring });
