// Shared primitives: cipher-scramble text, copy button, key icon, etc.

// Text that animates in as a cipher scramble. Triggers once when in view.
function CipherText({ text, className, style, delay = 0, duration = 900, charset }) {
  const ref = React.useRef(null);
  const [display, setDisplay] = React.useState(text);
  const [started, setStarted] = React.useState(false);
  const chars = charset || 'ABCDEFGHJKLMNPQRSTUVWXYZ0123456789/+=*#$%@';

  React.useEffect(() => {
    if (!ref.current) return;
    const io = new IntersectionObserver(([e]) => {
      if (e.isIntersecting && !started) setStarted(true);
    }, { threshold: 0.4 });
    io.observe(ref.current);
    return () => io.disconnect();
  }, [started]);

  React.useEffect(() => {
    if (!started) return;
    let raf, start;
    const tick = (t) => {
      if (!start) start = t + delay;
      const p = Math.max(0, Math.min(1, (t - start) / duration));
      const revealed = Math.floor(p * text.length);
      let out = '';
      for (let i = 0; i < text.length; i++) {
        if (i < revealed) out += text[i];
        else if (text[i] === ' ') out += ' ';
        else out += chars[Math.floor(Math.random() * chars.length)];
      }
      setDisplay(out);
      if (p < 1) raf = requestAnimationFrame(tick);
      else setDisplay(text);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [started, text, delay, duration]);

  return <span ref={ref} className={className} style={style}>{display}</span>;
}

// Small copy-to-clipboard button with flash feedback
function CopyBtn({ value, tone = 'dark' }) {
  const [copied, setCopied] = React.useState(false);
  const onClick = (e) => {
    e.stopPropagation();
    try {
      navigator.clipboard.writeText(value);
      setCopied(true);
      setTimeout(() => setCopied(false), 1100);
    } catch (e) {}
  };
  const dark = tone === 'dark';
  return (
    <button onClick={onClick} style={{
      appearance:'none', border:'none', background:'transparent',
      width:22, height:22, borderRadius:9, cursor:'pointer',
      display:'inline-flex', alignItems:'center', justifyContent:'center',
      color: dark ? (copied ? '#4ade80' : 'rgba(255,255,255,.55)') : (copied ? '#10b981' : 'rgba(0,0,0,.45)'),
      transition:'color .15s',
    }} title="Copy">
      {copied ? (
        <svg width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="3 8 7 12 13 4"/></svg>
      ) : (
        <svg width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.6"><rect x="5" y="5" width="8" height="9" rx="1.3"/><path d="M3 11V3a1 1 0 0 1 1-1h7"/></svg>
      )}
    </button>
  );
}

function EyeBtn({ shown, onClick, tone = 'dark' }) {
  const dark = tone === 'dark';
  return (
    <button onClick={(e) => { e.stopPropagation(); onClick(); }} style={{
      appearance:'none', border:'none', background:'transparent',
      width:22, height:22, borderRadius:9, cursor:'pointer',
      display:'inline-flex', alignItems:'center', justifyContent:'center',
      color: dark ? 'rgba(255,255,255,.55)' : 'rgba(0,0,0,.45)',
    }} title={shown ? 'Hide' : 'Reveal'}>
      {shown ? (
        <svg width="13" height="13" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round">
          <path d="M2 8s2.5-4.5 6-4.5S14 8 14 8s-2.5 4.5-6 4.5S2 8 2 8Z"/><circle cx="8" cy="8" r="1.8"/>
        </svg>
      ) : (
        <svg width="13" height="13" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round">
          <path d="M2 8s2.5-4.5 6-4.5S14 8 14 8s-2.5 4.5-6 4.5S2 8 2 8Z"/><path d="M3 3l10 10"/>
        </svg>
      )}
    </button>
  );
}

// Mask: show first N, then ••••, last M. Hover-reveal via shown prop.
function MaskedValue({ value, shown, head = 3, tail = 6, tone = 'dark' }) {
  if (shown) return <span>{value}</span>;
  const start = value.slice(0, head);
  const end = value.slice(-tail);
  return <span>{start}<span style={{letterSpacing:'.05em'}}>••••••••</span>{end}</span>;
}

// Shield / key logo — authoritative brand mark
// The shield path is a closed geometric form with a negative-space "corner" cut;
// fill is a fixed purple→indigo gradient to stay consistent across surfaces.
// `accent` prop is retained for backwards compat (affects the glow halo only).
function ShieldLogo({ size = 44, accent = '#8b7cff', glow = true }) {
  const gid = `shield-grad-${String(accent).slice(1)}-${Math.round(size)}`;
  return (
    <svg width={size} height={size} viewBox="0 0 64 64" fill="none"
         style={{ filter: glow ? `drop-shadow(0 0 14px ${accent}44)` : 'none', display:'block' }}>
      <defs>
        <linearGradient id={gid} x1="11.52" y1="10.75" x2="49.68" y2="53.40" gradientUnits="userSpaceOnUse">
          <stop offset="0" stopColor="#AE84FC"/>
          <stop offset="1" stopColor="#6681FE"/>
        </linearGradient>
      </defs>
      <path fill={`url(#${gid})`} d="M59.9746 13.7959C59.9746 11.2338 58.411 9.48635 55.7569 9.1316L54.627 9.00021C53.116 8.81626 51.6707 8.64545 50.3174 8.34326C45.3377 7.23958 40.5289 4.97968 35.1813 1.2482C34.3404 0.656949 33.4075 0 32.0411 0C30.6746 0 29.7286 0.656949 28.914 1.23506C21.7664 6.17532 15.3283 8.65859 8.70624 9.03962C6.95876 9.11846 4.0419 9.86738 4.0419 13.9667L4.02876 20.6151C4.01563 25.0955 4.00249 29.589 4.0419 34.0563C4.0419 35.8563 4.26527 37.7352 4.72513 39.8243C5.73683 44.3047 8.10185 48.3909 11.9647 52.3326C16.7079 57.1414 22.6861 60.8598 30.3724 63.7504C30.8849 63.9212 31.4235 64 31.9754 64C32.7374 64 33.4864 63.8292 34.0119 63.5664L35.9565 62.7124C37.5595 62.016 39.1624 61.3196 40.8048 60.505C46.8487 57.3385 51.4736 53.5151 54.9292 48.8507C57.9906 44.8171 59.6461 40.4944 59.8432 36.0271C59.9877 33.0314 59.9877 29.9963 59.9746 27.0663V13.7959ZM53.1292 35.738C52.9846 38.8783 51.8284 41.8477 49.5422 44.8434C46.6779 48.7062 42.8019 51.8859 37.7303 54.5531C36.2587 55.2889 34.7609 55.9327 33.2761 56.5765C32.8557 56.7604 32.4353 56.9444 31.9885 57.1414V32.5978H10.7692C10.7429 28.6036 10.7429 24.6225 10.7561 20.6413L10.7692 15.6091C17.8511 14.8733 24.6571 12.193 31.9887 7.25272V32.5847H53.195C53.1948 33.6489 53.1818 34.7001 53.1292 35.738Z"/>
    </svg>
  );
}

// Wordmark — distinctive mixed typography for "CypherKeep".
// Uses Instrument Serif (already loaded for the hero) for "Cypher" and
// Geist for "Keep", giving the brand a two-tone editorial / utility feel
// without adding font weight to the page. Size scales from a single prop.
function Wordmark({ size = 22, color = 'inherit' }) {
  return (
    <span style={{
      fontSize: size,
      fontFamily: "'Geist', system-ui, sans-serif",
      letterSpacing: '-.025em',
      color,
      lineHeight: 1,
      whiteSpace: 'nowrap',
    }}>
      <span style={{ fontWeight: 500 }}>Cypher</span><span style={{ fontWeight: 700 }}>Keep</span>
    </span>
  );
}

// Apple-logo for download CTA (generic glyph, not an Apple trademark recreation)
function DownloadMark({ size = 14, color = 'currentColor' }) {
  return (
    <svg width={size} height={size} viewBox="0 0 16 16" fill="none" stroke={color} strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
      <path d="M8 2 V11"/><path d="M4 8 L8 12 L12 8"/><path d="M3 14 H13"/>
    </svg>
  );
}

// Key glyph for app icons
function KeyGlyph({ size = 14, color = 'currentColor' }) {
  return (
    <svg width={size} height={size} viewBox="0 0 16 16" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round">
      <circle cx="5.5" cy="8" r="2.5"/><path d="M8 8 H14"/><path d="M11 8 V10"/><path d="M13 8 V11"/>
    </svg>
  );
}

// Seed-phrase word pill
function SeedChip({ n, word, tone = 'dark' }) {
  const dark = tone === 'dark';
  return (
    <div style={{
      display:'flex', alignItems:'center', gap:8,
      padding:'6px 10px', borderRadius:16,
      background: dark ? 'rgba(255,255,255,.04)' : 'rgba(0,0,0,.04)',
      border: `1px solid ${dark ? 'rgba(255,255,255,.07)' : 'rgba(0,0,0,.06)'}`,
      fontFamily: "'Geist Mono', monospace", fontSize: 12,
      color: dark ? 'rgba(255,255,255,.9)' : 'rgba(0,0,0,.82)',
    }}>
      <span style={{ color: dark ? 'rgba(255,255,255,.35)' : 'rgba(0,0,0,.35)', fontSize: 10 }}>{String(n).padStart(2,'0')}</span>
      <span>{word}</span>
    </div>
  );
}

// Hook: reveal-on-scroll fade+rise
function useReveal(threshold = 0.15) {
  const ref = React.useRef(null);
  const [seen, setSeen] = React.useState(false);
  React.useEffect(() => {
    if (!ref.current) return;
    const io = new IntersectionObserver(([e]) => {
      if (e.isIntersecting) setSeen(true);
    }, { threshold });
    io.observe(ref.current);
    return () => io.disconnect();
  }, [threshold]);
  return [ref, seen];
}

function Reveal({ children, delay = 0, y = 16, style }) {
  const [ref, seen] = useReveal();
  return (
    <div ref={ref} style={{
      transform: seen ? 'translateY(0)' : `translateY(${y}px)`,
      opacity: seen ? 1 : 0,
      transition: `opacity .7s cubic-bezier(.2,.7,.3,1) ${delay}ms, transform .8s cubic-bezier(.2,.7,.3,1) ${delay}ms`,
      ...style,
    }}>{children}</div>
  );
}

Object.assign(window, { CipherText, CopyBtn, EyeBtn, MaskedValue, ShieldLogo, Wordmark, DownloadMark, KeyGlyph, SeedChip, useReveal, Reveal });
