/* Shared visual primitives — waveforms, icons, signal lanes */
const { useState, useEffect, useRef, useMemo } = React;

/* SVG icon set — strokes only, ultra-minimal */
function Icon({ name, size = 16, color = "currentColor", style }) {
  const common = { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: 1.5, strokeLinecap: "round", strokeLinejoin: "round", style };
  switch (name) {
    case "search":
      return <svg {...common}><circle cx="11" cy="11" r="7"/><path d="M20 20l-3.5-3.5"/></svg>;
    case "command":
      return <svg {...common}><path d="M9 6a3 3 0 1 0-3 3h12a3 3 0 1 0-3-3v12a3 3 0 1 0 3-3H6a3 3 0 1 0 3 3V6z"/></svg>;
    case "play":
      return <svg {...common} fill={color} stroke="none"><path d="M8 5v14l11-7z"/></svg>;
    case "pause":
      return <svg {...common}><path d="M10 5v14M15 5v14"/></svg>;
    case "skip":
      return <svg {...common}><path d="M5 5v14M19 5L9 12l10 7z"/></svg>;
    case "arrow":
      return <svg {...common}><path d="M5 12h14M13 6l6 6-6 6"/></svg>;
    case "spark":
      return <svg {...common}><path d="M12 3v4M12 17v4M3 12h4M17 12h4M5.5 5.5l2.8 2.8M15.7 15.7l2.8 2.8M5.5 18.5l2.8-2.8M15.7 8.3l2.8-2.8"/></svg>;
    case "code":
      return <svg {...common}><path d="M8 7l-5 5 5 5M16 7l5 5-5 5"/></svg>;
    case "loop":
      return <svg {...common}><path d="M3 7h13a4 4 0 0 1 0 8H7M7 11l-4 4 4 4"/></svg>;
    default: return null;
  }
}

/* Static decorative waveform — pure SVG, no random per-render to avoid hydration jitter */
function MiniWave({ width = 84, height = 22, color = "currentColor", seed = 1, peaks = 22 }) {
  const path = useMemo(() => {
    const rng = mulberry(seed);
    const step = width / (peaks - 1);
    let d = "";
    for (let i = 0; i < peaks; i++) {
      const x = i * step;
      const t = i / (peaks - 1);
      const envelope = Math.sin(t * Math.PI) * 0.85 + 0.15;
      const h = (rng() * 0.7 + 0.3) * envelope * (height * 0.45);
      d += `M${x.toFixed(2)} ${(height/2 - h).toFixed(2)} L${x.toFixed(2)} ${(height/2 + h).toFixed(2)} `;
    }
    return d;
  }, [width, height, seed, peaks]);
  return (
    <svg width={width} height={height} viewBox={`0 0 ${width} ${height}`} aria-hidden="true">
      <path d={path} stroke={color} strokeWidth="1.2" strokeLinecap="round" opacity="0.7" />
    </svg>
  );
}

function mulberry(seed) {
  let a = seed | 0;
  return function() {
    a |= 0; a = a + 0x6D2B79F5 | 0;
    let t = a;
    t = Math.imul(t ^ t >>> 15, t | 1);
    t ^= t + Math.imul(t ^ t >>> 7, t | 61);
    return ((t ^ t >>> 14) >>> 0) / 4294967296;
  }
}

/* Animated breathing signal lane used in the layered-signals section.
   Each lane is a different "channel" of conversation. */
function SignalLane({ kind, color, seed = 7, markers = [] }) {
  // kind: "wave" | "step" | "dots" | "spikes" | "ribbon" | "events" | "scribble"
  const ref = useRef(null);
  const [t, setT] = useState(0);
  useEffect(() => {
    let raf, start = performance.now();
    const loop = (now) => {
      setT((now - start) / 1000);
      raf = requestAnimationFrame(loop);
    };
    raf = requestAnimationFrame(loop);
    return () => cancelAnimationFrame(raf);
  }, []);

  const W = 900, H = 36;
  const rng = useMemo(() => mulberry(seed), [seed]);
  const points = useMemo(() => Array.from({ length: 120 }, (_, i) => rng()), [rng]);

  let body = null;
  if (kind === "wave") {
    const d = points.map((p, i) => {
      const x = (i / (points.length - 1)) * W;
      const phase = t * 0.6 + i * 0.18;
      const y = H/2 + Math.sin(phase) * (4 + p * 8);
      return `${i === 0 ? "M" : "L"}${x.toFixed(1)} ${y.toFixed(1)}`;
    }).join(" ");
    body = <path d={d} stroke={color} strokeWidth="1.2" fill="none" opacity="0.85" />;
  } else if (kind === "spikes") {
    body = points.map((p, i) => {
      const x = (i / (points.length - 1)) * W;
      const h = p > 0.78 ? (p * 18 + 4) : 1.5;
      return <line key={i} x1={x} y1={H/2 - h} x2={x} y2={H/2 + h} stroke={color} strokeWidth="1" opacity={p > 0.78 ? 0.95 : 0.35}/>;
    });
  } else if (kind === "step") {
    let d = `M0 ${H/2}`;
    points.slice(0, 30).forEach((p, i) => {
      const x = ((i+1) / 30) * W;
      const y = H/2 + (p - 0.5) * 18;
      d += ` H${x.toFixed(1)} V${y.toFixed(1)}`;
    });
    body = <path d={d} stroke={color} strokeWidth="1.2" fill="none" opacity="0.85"/>;
  } else if (kind === "dots") {
    body = points.map((p, i) => {
      const x = (i / (points.length - 1)) * W;
      const r = p > 0.5 ? 1.6 : 1;
      const yJitter = Math.sin(t * 1.2 + i) * 2.5;
      return <circle key={i} cx={x} cy={H/2 + yJitter * (p - 0.5)} r={r} fill={color} opacity={0.55}/>;
    });
  } else if (kind === "ribbon") {
    const top = points.map((p, i) => {
      const x = (i / (points.length - 1)) * W;
      const y = H/2 - 3 - Math.sin(t * 0.4 + i * 0.2) * (2 + p * 4);
      return `${i === 0 ? "M" : "L"}${x.toFixed(1)} ${y.toFixed(1)}`;
    }).join(" ");
    const bot = points.slice().reverse().map((p, i) => {
      const realI = points.length - 1 - i;
      const x = (realI / (points.length - 1)) * W;
      const y = H/2 + 3 + Math.sin(t * 0.4 + realI * 0.2 + 1.4) * (2 + p * 4);
      return `L${x.toFixed(1)} ${y.toFixed(1)}`;
    }).join(" ");
    body = <path d={`${top} ${bot} Z`} fill={color} opacity="0.18" stroke={color} strokeOpacity="0.5" strokeWidth="0.8"/>;
  } else if (kind === "events") {
    const events = [0.08, 0.21, 0.34, 0.47, 0.62, 0.78, 0.92];
    body = events.map((e, i) => (
      <g key={i}>
        <line x1={e * W} y1={6} x2={e * W} y2={H - 6} stroke={color} strokeWidth="1" opacity="0.65"/>
        <circle cx={e * W} cy={H/2} r="2.4" fill={color} opacity={0.85}/>
      </g>
    ));
  } else if (kind === "scribble") {
    const d = points.map((p, i) => {
      const x = (i / (points.length - 1)) * W;
      const y = H/2 + Math.sin(t * 1.4 + i * 0.7) * (p * 10) + (p - 0.5) * 6;
      return `${i === 0 ? "M" : "L"}${x.toFixed(1)} ${y.toFixed(1)}`;
    }).join(" ");
    body = <path d={d} stroke={color} strokeWidth="1.1" fill="none" opacity="0.7"/>;
  }
  /* === New per-row distinctive shapes (Most-systems-see-transcripts section) === */
  else if (kind === "blockwave") {
    // Realistic audio-waveform: varied amplitudes, dynamic envelope, occasional micro-gaps
    const N = 140;
    // Pre-defined gap windows so it reads as speech with brief pauses
    const gaps = [[0.12, 0.14], [0.39, 0.42], [0.71, 0.735]];
    body = Array.from({ length: N }, (_, i) => {
      const tt = i / (N - 1);
      const inGap = gaps.some(([a, b]) => tt >= a && tt <= b);
      if (inGap) return null;
      const p = points[i % points.length];
      const q = points[(i * 5 + 13) % points.length];
      // Envelope: macro speech bursts + micro variation
      const macro = 0.45 + 0.55 * Math.abs(Math.sin(tt * Math.PI * 3.3 + 0.6));
      const accent = (i % 17 === 3 || i % 23 === 5) ? 1.35 : 1.0;
      const h = (1 + (p * 0.7 + q * 0.3) * 13) * macro * accent;
      return <line key={i} x1={tt * W} y1={H/2 - h} x2={tt * W} y2={H/2 + h} stroke={color} strokeWidth="1" opacity="0.62"/>;
    });
  } else if (kind === "ticks") {
    // Sparse vertical tick marks at interruption moments
    const positions = [0.11, 0.28, 0.44, 0.59, 0.73, 0.88];
    body = positions.map((p, i) => (
      <line key={i} x1={p*W} y1={5} x2={p*W} y2={H-5} stroke={color} strokeWidth="1.4" opacity="0.85"/>
    ));
  } else if (kind === "gaps") {
    // Quiet waveform punctured by explicit silent stretches
    const silences = [[0.18, 0.31], [0.56, 0.69]];
    const bars = points.slice(0, 110).map((p, i) => {
      const tt = i / 109;
      const inSilence = silences.some(([a,b]) => tt >= a && tt <= b);
      if (inSilence) return null;
      const x = tt * W;
      const h = 2 + p * 7;
      return <line key={i} x1={x} y1={H/2 - h} x2={x} y2={H/2 + h} stroke={color} strokeWidth="0.9" opacity="0.55"/>;
    });
    body = (
      <g>
        {silences.map(([a,b], i) => (
          <g key={"sil"+i}>
            <line x1={a*W} y1={H/2} x2={b*W} y2={H/2} stroke={color} strokeWidth="0.8" strokeDasharray="2 3" opacity="0.35"/>
            <text x={(a+b)/2 * W} y={H - 2} textAnchor="middle" fontFamily="Geist Mono" fontSize="8.5" fill="var(--mute)" opacity="0.7">silence</text>
          </g>
        ))}
        {bars}
      </g>
    );
  } else if (kind === "dotbursts") {
    // Short clusters of dots — hesitations
    const bursts = [0.13, 0.32, 0.51, 0.68, 0.86];
    body = bursts.flatMap((center, ci) =>
      Array.from({ length: 5 }, (_, j) => {
        const offset = (j - 2) * 3.5;
        const x = center * W + offset;
        const yJit = ((j * 7 + ci * 11) % 7 - 3) * 1.1;
        return <circle key={`${ci}-${j}`} cx={x} cy={H/2 + yJit} r="1.3" fill={color} opacity="0.75"/>;
      })
    );
  } else if (kind === "smoothwave") {
    // Single smooth continuous line — tone/sentiment
    const N = 100;
    const d = Array.from({ length: N }, (_, i) => {
      const x = (i / (N - 1)) * W;
      const y = H/2
        + Math.sin(t * 0.35 + i * 0.10) * 5
        + Math.sin(i * 0.04 + 1.3) * 4
        + Math.cos(i * 0.018) * 2;
      return `${i === 0 ? "M" : "L"}${x.toFixed(1)} ${y.toFixed(1)}`;
    }).join(" ");
    body = <path d={d} stroke={color} strokeWidth="1.3" fill="none" opacity="0.85" strokeLinecap="round"/>;
  } else if (kind === "densitybars") {
    // Vertical density bars — pacing/overlap
    const N = 56;
    body = Array.from({ length: N }, (_, i) => {
      const x = (i / (N - 1)) * W;
      const p = points[i % points.length];
      const q = points[(i * 3 + 7) % points.length];
      const h = (p * 0.65 + q * 0.35) * 14 + 2;
      return <line key={i} x1={x} y1={H/2 - h} x2={x} y2={H/2 + h} stroke={color} strokeWidth="1.6" opacity="0.65"/>;
    });
  } else if (kind === "latencybars") {
    // Vertical bars at event times — red for >4s outliers
    const events = [
      { x: 0.08, lat: 0.6 },
      { x: 0.19, lat: 1.1 },
      { x: 0.32, lat: 1.8 },
      { x: 0.46, lat: 4.24, slow: true },
      { x: 0.58, lat: 1.4 },
      { x: 0.70, lat: 0.9 },
      { x: 0.81, lat: 4.8,  slow: true },
      { x: 0.94, lat: 1.2 },
    ];
    body = events.map((e, i) => {
      const h = Math.min(15, e.lat * 3.2 + 2);
      return (
        <line key={i}
          x1={e.x * W} y1={H/2 - h}
          x2={e.x * W} y2={H/2 + h}
          stroke={e.slow ? "var(--warn)" : color}
          strokeWidth={e.slow ? 1.9 : 1.2}
          opacity={e.slow ? 0.95 : 0.55}/>
      );
    });
  } else if (kind === "recoverysteps") {
    // Step function with red drop markers on the two failed recoveries
    const steps = [
      { x: 0.00, y: 0.50 },
      { x: 0.15, y: 0.45 },
      { x: 0.30, y: 0.42 },
      { x: 0.34, y: 0.78, failed: true },
      { x: 0.48, y: 0.46 },
      { x: 0.62, y: 0.44 },
      { x: 0.66, y: 0.80, failed: true },
      { x: 0.80, y: 0.48 },
      { x: 1.00, y: 0.50 },
    ];
    let d = `M0 ${(steps[0].y * H).toFixed(1)}`;
    for (let i = 1; i < steps.length; i++) {
      const xi = steps[i].x * W;
      const yi = steps[i].y * H;
      const prevY = steps[i-1].y * H;
      d += ` L${xi.toFixed(1)} ${prevY.toFixed(1)} L${xi.toFixed(1)} ${yi.toFixed(1)}`;
    }
    body = (
      <g>
        <path d={d} stroke={color} strokeWidth="1.1" fill="none" opacity="0.7"/>
        {steps.filter(s => s.failed).map((s, i) => (
          <g key={"f"+i}>
            <line x1={s.x * W} y1={H/2 - 14} x2={s.x * W} y2={H/2 + 14}
                  stroke="var(--warn)" strokeWidth="1.2" opacity="0.6"/>
            <circle cx={s.x * W} cy={s.y * H} r="3" fill="var(--warn)" opacity="0.95"/>
          </g>
        ))}
      </g>
    );
  }

  return (
    <svg ref={ref} viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="none" width="100%" height={H} aria-hidden="true">
      {body}
      {markers.map((m, i) => (
        <g key={i}>
          <line x1={m * W} y1={2} x2={m * W} y2={H - 2} stroke="var(--ink)" strokeOpacity="0.18" strokeWidth="1" strokeDasharray="2 3"/>
        </g>
      ))}
    </svg>
  );
}

/* A grouped waveform used inside the replay panel — multi-channel + playhead */
function ReplayWave({ playhead = 0.25, events = [], activeIndex = null, onSelectEvent }) {
  const W = 900, H = 130;
  const GUTTER = 78;
  const WAVE_W = W - GUTTER;
  const CALLER_Y = 42;
  const AGENT_Y  = 96;
  const LANE_H   = 26;

  const eventX = (pos) => GUTTER + pos * WAVE_W;

  /* Speech envelope — bursts where someone is talking, near-zero otherwise. */
  const envelope = (t, ranges) => {
    for (const [a, b] of ranges) {
      if (t >= a && t <= b) {
        const local = (t - a) / (b - a);
        return Math.sin(local * Math.PI) * 0.92 + 0.05;
      }
    }
    return 0.04;
  };

  /* Caller: greeting/booking → push-back after interruption → frustrated retry after silence */
  const CALLER_RANGES = [[0.02, 0.22], [0.28, 0.34], [0.58, 0.66]];
  /* Agent: partial read-back (overlap = barge-in) → recovery → tool wait → resolution */
  const AGENT_RANGES  = [[0.18, 0.27], [0.35, 0.44], [0.68, 0.78], [0.82, 0.94]];

  const rng1 = useMemo(() => mulberry(11), []);
  const rng2 = useMemo(() => mulberry(29), []);
  const N = 200;
  const a = useMemo(
    () => Array.from({ length: N }, (_, i) => rng1() * envelope(i / (N - 1), CALLER_RANGES)),
    []
  );
  const b = useMemo(
    () => Array.from({ length: N }, (_, i) => rng2() * envelope(i / (N - 1), AGENT_RANGES)),
    []
  );

  const callerColor = "oklch(0.55 0.12 245)";  // cool blue
  const agentColor  = "oklch(0.50 0.06 30)";   // warm neutral (won't compete with amber events)
  const eventColor  = "oklch(0.66 0.16 65)";   // amber — every failure moment
  const eventColorActive = "oklch(0.62 0.20 60)"; // slightly deeper amber
  const playheadColor = "oklch(0.50 0.15 245)"; // saturated blue cursor

  return (
    <svg viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="none" width="100%" height={H} style={{ display: "block" }}>
      {/* Event spans — amber tints (active brighter, inactive faint) */}
      {events.map((ev, i) => {
        if (!ev.span) return null;
        const isActive = i === activeIndex;
        return (
          <rect key={"sp"+i}
            x={eventX(ev.pos)}
            y="0"
            width={ev.span * WAVE_W}
            height={H}
            fill={eventColor}
            opacity={isActive ? 0.14 : 0.06}/>
        );
      })}

      {/* Subtle vertical gridlines */}
      {[0.25, 0.5, 0.75].map((p, i) => (
        <line key={"g"+i}
          x1={eventX(p)} y1="8"
          x2={eventX(p)} y2={H - 4}
          stroke="var(--hair)" strokeWidth="1"/>
      ))}

      {/* Track labels */}
      <text x="14" y={CALLER_Y + 4}
        fontFamily="Geist Mono" fontSize="11.5"
        fill="var(--ink-soft)" letterSpacing="0.06em"
        fontWeight="500">CALLER</text>
      <text x="14" y={AGENT_Y + 4}
        fontFamily="Geist Mono" fontSize="11.5"
        fill="var(--ink-soft)" letterSpacing="0.06em"
        fontWeight="500">AGENT</text>

      {/* Caller wave — cool blue */}
      {a.map((v, i) => {
        const x = GUTTER + (i / (N - 1)) * WAVE_W;
        const h = v * LANE_H + 0.6;
        return (
          <line key={"ca"+i}
            x1={x} y1={CALLER_Y - h}
            x2={x} y2={CALLER_Y + h}
            stroke={callerColor} strokeWidth="1" opacity="0.78"/>
        );
      })}

      {/* Agent wave — warm neutral */}
      {b.map((v, i) => {
        const x = GUTTER + (i / (N - 1)) * WAVE_W;
        const h = v * LANE_H + 0.6;
        return (
          <line key={"ag"+i}
            x1={x} y1={AGENT_Y - h}
            x2={x} y2={AGENT_Y + h}
            stroke={agentColor} strokeWidth="1" opacity="0.80"/>
        );
      })}

      {/* Event ticks — amber vertical lines at the start of each event */}
      {events.map((ev, i) => {
        const isActive = i === activeIndex;
        const x = eventX(ev.pos);
        return (
          <line key={"tk"+i}
            x1={x} y1="0"
            x2={x} y2={H}
            stroke={isActive ? eventColorActive : eventColor}
            strokeWidth={isActive ? 1.4 : 1}
            opacity={isActive ? 0.95 : 0.55}/>
        );
      })}

      {/* Playhead — blue thin cursor (distinct from amber evidence) */}
      <line
        x1={eventX(playhead)} y1="0"
        x2={eventX(playhead)} y2={H}
        stroke={playheadColor} strokeWidth="1"
        strokeDasharray="0"/>
      <polygon
        points={`${eventX(playhead)-4.5},0 ${eventX(playhead)+4.5},0 ${eventX(playhead)},6`}
        fill={playheadColor}/>

      {/* Generous click targets on events */}
      {events.map((ev, i) => (
        <rect
          key={"hit"+i}
          x={eventX(ev.pos) - 14} y="0"
          width="28" height={H}
          fill="transparent"
          style={{ cursor: onSelectEvent ? "pointer" : "default" }}
          onClick={() => onSelectEvent && onSelectEvent(i)}/>
      ))}
    </svg>
  );
}

/* Logo dot mark for integrations row */
function IntegMark({ tone = "a" }) {
  const grads = {
    a: ["var(--accent-a)", "var(--accent-c)"],
    b: ["var(--accent-b)", "var(--accent-a)"],
    c: ["var(--accent-c)", "var(--accent-b)"],
    d: ["var(--accent-a)", "var(--accent-b)"],
  };
  const [from, to] = grads[tone] || grads.a;
  return (
    <span className="mark" style={{ background: `linear-gradient(135deg, color-mix(in oklab, ${from} 65%, var(--panel)), color-mix(in oklab, ${to} 55%, var(--panel)))` }}/>
  );
}

Object.assign(window, { Icon, MiniWave, SignalLane, ReplayWave, IntegMark, mulberry });
