// Shared thinking / streaming primitives.
// <ThinkingInk>   — inline "coach is reading…" indicator with a drifting nib.
// <SkelLines>     — stacked skeleton lines for streaming content.
// <StreamReveal>  — wraps a text node; swaps a skeleton out for text with a soft ink-bleed.
//
// All components are plain React; no state outside what they own.

function ThinkingInk({ label = 'thinking…', mono = false, style }) {
  return (
    <span className="thinking-ink" style={style}>
      <span className="thinking-ink__nib" />
      <span className={mono ? '' : 'thinking-ink__label'}>{label}</span>
    </span>
  );
}

function SkelLines({ lines = 3, widths = null, gap = 8 }) {
  // widths is an optional array of % strings; defaults to a tapered look
  const defaults = ['92%', '86%', '70%', '48%', '58%'];
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap }}>
      {Array.from({ length: lines }).map((_, i) => (
        <div
          key={i}
          className="skel-line"
          style={{ width: (widths && widths[i]) || defaults[i % defaults.length] }}
        />
      ))}
    </div>
  );
}

// A helper: given a partial string that may grow token-by-token, render each
// "new" chunk with stream-reveal so incoming text softly bleeds in.
// Tracks the previous length on a ref to emit only the delta class.
function StreamingText({ text, className, style }) {
  const ref = React.useRef({ prev: '' });
  // force a remount-ish reveal each time text meaningfully grows by wrapping
  // the new tail in a <span class="stream-reveal">.
  const prev = ref.current.prev;
  let head = prev;
  let tail = '';
  if (text && text.startsWith(prev) && text.length > prev.length) {
    tail = text.slice(prev.length);
  } else {
    // text changed non-monotonically (e.g. a partial JSON reparse replaced the string);
    // render it whole and treat it as a fresh reveal.
    head = '';
    tail = text || '';
  }
  ref.current.prev = text || '';
  return (
    <span className={className} style={style}>
      {head}
      {tail && <span className="stream-reveal" key={head.length}>{tail}</span>}
    </span>
  );
}

Object.assign(window, { ThinkingInk, SkelLines, StreamingText });
console.log('[cg] thinking primitives loaded');
