// shared.jsx — tokens, shared components, sfx

const TOKENS = {
  bg: '#faf7f2',
  ink: '#1a1814',
  inkSoft: '#5a544a',
  // Playful diagram-inspired palette
  blue:   'oklch(78% 0.10 230)', // step 1 — camera / photo
  tan:    'oklch(85% 0.07 85)',  // step 2 — ChatGPT (warm neutral)
  coral:  'oklch(74% 0.15 35)',  // step 3 — Nano Banana
  lavender:'oklch(76% 0.10 295)',// step 4 — Kling
  teal:   'oklch(52% 0.08 210)', // end-card accent
  lemon:  'oklch(92% 0.14 95)',  // accent
  mint:   'oklch(86% 0.10 160)', // accent
  display: '"Space Grotesk", Inter, system-ui, sans-serif',
  mono: '"JetBrains Mono", ui-monospace, monospace',
};

// ───────────────────────────────────────────────────────────
// SFX — WebAudio synth (click, whoosh, ding, shutter, type)
// Silent until user first interacts (browser autoplay policy).
// ───────────────────────────────────────────────────────────
const Sfx = (() => {
  let ctx = null;
  const getCtx = () => {
    if (!ctx) {
      try {
        ctx = new (window.AudioContext || window.webkitAudioContext)();
      } catch { return null; }
    }
    if (ctx.state === 'suspended') ctx.resume();
    return ctx;
  };

  const click = (when = 0, pitch = 800) => {
    const a = getCtx(); if (!a) return;
    const t = a.currentTime + when;
    const o = a.createOscillator(); const g = a.createGain();
    o.type = 'triangle'; o.frequency.setValueAtTime(pitch, t);
    o.frequency.exponentialRampToValueAtTime(pitch * 0.5, t + 0.04);
    g.gain.setValueAtTime(0.18, t);
    g.gain.exponentialRampToValueAtTime(0.001, t + 0.06);
    o.connect(g).connect(a.destination);
    o.start(t); o.stop(t + 0.08);
  };

  const whoosh = (when = 0, dur = 0.4) => {
    const a = getCtx(); if (!a) return;
    const t = a.currentTime + when;
    const buf = a.createBuffer(1, Math.floor(a.sampleRate * dur), a.sampleRate);
    const data = buf.getChannelData(0);
    for (let i = 0; i < data.length; i++) {
      const p = i / data.length;
      data[i] = (Math.random() * 2 - 1) * Math.sin(p * Math.PI) * 0.35;
    }
    const src = a.createBufferSource(); src.buffer = buf;
    const filter = a.createBiquadFilter();
    filter.type = 'bandpass'; filter.Q.value = 1.2;
    filter.frequency.setValueAtTime(400, t);
    filter.frequency.exponentialRampToValueAtTime(1800, t + dur);
    const g = a.createGain();
    g.gain.setValueAtTime(0.0001, t);
    g.gain.exponentialRampToValueAtTime(0.22, t + dur * 0.3);
    g.gain.exponentialRampToValueAtTime(0.001, t + dur);
    src.connect(filter).connect(g).connect(a.destination);
    src.start(t); src.stop(t + dur);
  };

  const shutter = (when = 0) => {
    const a = getCtx(); if (!a) return;
    const t = a.currentTime + when;
    // Quick burst of noise
    const buf = a.createBuffer(1, Math.floor(a.sampleRate * 0.12), a.sampleRate);
    const data = buf.getChannelData(0);
    for (let i = 0; i < data.length; i++) data[i] = (Math.random() * 2 - 1) * 0.9;
    const src = a.createBufferSource(); src.buffer = buf;
    const hp = a.createBiquadFilter(); hp.type = 'highpass'; hp.frequency.value = 1200;
    const g = a.createGain();
    g.gain.setValueAtTime(0.35, t);
    g.gain.exponentialRampToValueAtTime(0.001, t + 0.11);
    src.connect(hp).connect(g).connect(a.destination);
    src.start(t); src.stop(t + 0.12);
  };

  const ding = (when = 0, pitch = 880) => {
    const a = getCtx(); if (!a) return;
    const t = a.currentTime + when;
    const o = a.createOscillator(); const g = a.createGain();
    o.type = 'sine'; o.frequency.setValueAtTime(pitch, t);
    g.gain.setValueAtTime(0.0001, t);
    g.gain.exponentialRampToValueAtTime(0.22, t + 0.01);
    g.gain.exponentialRampToValueAtTime(0.001, t + 0.5);
    o.connect(g).connect(a.destination);
    o.start(t); o.stop(t + 0.52);
    // overtone
    const o2 = a.createOscillator(); const g2 = a.createGain();
    o2.type = 'sine'; o2.frequency.setValueAtTime(pitch * 1.5, t);
    g2.gain.setValueAtTime(0.0001, t);
    g2.gain.exponentialRampToValueAtTime(0.1, t + 0.01);
    g2.gain.exponentialRampToValueAtTime(0.001, t + 0.35);
    o2.connect(g2).connect(a.destination);
    o2.start(t); o2.stop(t + 0.4);
  };

  const pop = (when = 0, pitch = 440) => {
    const a = getCtx(); if (!a) return;
    const t = a.currentTime + when;
    const o = a.createOscillator(); const g = a.createGain();
    o.type = 'sine';
    o.frequency.setValueAtTime(pitch * 0.5, t);
    o.frequency.exponentialRampToValueAtTime(pitch * 2, t + 0.08);
    g.gain.setValueAtTime(0.18, t);
    g.gain.exponentialRampToValueAtTime(0.001, t + 0.12);
    o.connect(g).connect(a.destination);
    o.start(t); o.stop(t + 0.13);
  };

  return { click, whoosh, ding, shutter, pop };
})();

// Schedules sfx to fire based on playhead. Fires each cue once per "play-through".
// Pass cues as [{t: seconds, fn: () => Sfx.xxx()}].
function useSfxTimeline(cues) {
  const time = useTime();
  const { playing } = useTimeline();
  const firedRef = React.useRef(new Set());
  const lastTimeRef = React.useRef(0);

  React.useEffect(() => {
    // Detect scrubbing back → reset fired set
    if (time < lastTimeRef.current - 0.3) {
      firedRef.current = new Set();
    }
    lastTimeRef.current = time;

    if (!playing) return;
    cues.forEach((cue, i) => {
      const key = `${i}-${cue.t}`;
      if (!firedRef.current.has(key) && time >= cue.t && time < cue.t + 0.25) {
        firedRef.current.add(key);
        try { cue.fn(); } catch {}
      }
    });
  }, [time, playing, cues]);
}

// ───────────────────────────────────────────────────────────
// Visual primitives
// ───────────────────────────────────────────────────────────

// Silhouette avatar — simple head + shoulders + optional hair shape.
// hairStyle: 'short' | 'long' | 'afro' | 'mohawk' | 'none'
// hairColor: css color. Returns inline SVG.
function Silhouette({ hairStyle = 'short', hairColor = '#2a2320', skin = '#d9b896', shirt = '#4a6fa8', size = 320 }) {
  const vb = 200;
  return (
    <svg width={size} height={size} viewBox={`0 0 ${vb} ${vb}`} style={{ display: 'block' }}>
      {/* Shoulders */}
      <path d={`M 20 ${vb} Q 20 140 60 130 L 140 130 Q 180 140 180 ${vb} Z`} fill={shirt}/>
      {/* Neck */}
      <rect x="85" y="115" width="30" height="25" fill={skin}/>
      {/* Head */}
      <ellipse cx="100" cy="85" rx="38" ry="44" fill={skin}/>
      {/* Hair — varies */}
      {hairStyle === 'short' && (
        <path d="M 62 78 Q 62 45 100 43 Q 138 45 138 78 Q 138 65 120 62 Q 100 58 80 62 Q 62 65 62 78 Z" fill={hairColor}/>
      )}
      {hairStyle === 'long' && (
        <g fill={hairColor}>
          <path d="M 58 82 Q 55 42 100 40 Q 145 42 142 82 Q 148 120 140 155 L 150 155 Q 158 110 150 72 Q 142 35 100 33 Q 58 35 50 72 Q 42 110 50 155 L 60 155 Q 52 120 58 82 Z"/>
          <path d="M 62 72 Q 62 48 100 46 Q 138 48 138 72 Q 138 60 120 58 Q 100 54 80 58 Q 62 60 62 72 Z"/>
        </g>
      )}
      {hairStyle === 'afro' && (
        <g fill={hairColor}>
          <circle cx="100" cy="65" r="48"/>
          <circle cx="72" cy="72" r="22"/>
          <circle cx="128" cy="72" r="22"/>
          <circle cx="85" cy="48" r="18"/>
          <circle cx="115" cy="48" r="18"/>
        </g>
      )}
      {hairStyle === 'mohawk' && (
        <g fill={hairColor}>
          {/* Shaved sides stubble */}
          <path d="M 62 80 Q 62 58 78 52 L 78 80 Z" fill={hairColor} opacity="0.35"/>
          <path d="M 138 80 Q 138 58 122 52 L 122 80 Z" fill={hairColor} opacity="0.35"/>
          {/* Strip */}
          <path d="M 82 70 Q 80 28 100 22 Q 120 28 118 70 L 82 70 Z"/>
        </g>
      )}
    </svg>
  );
}

// Tool badge — colored rounded card with label + tiny mark.
function ToolBadge({ tool, size = 72 }) {
  const map = {
    camera:   { bg: TOKENS.blue,    label: 'Camera' },
    chatgpt:  { bg: TOKENS.tan,     label: 'ChatGPT' },
    banana:   { bg: TOKENS.coral,   label: 'Nano Banana' },
    kling:    { bg: TOKENS.lavender,label: 'Kling.ai' },
  };
  const m = map[tool];
  return (
    <div style={{
      width: size, height: size,
      background: m.bg,
      borderRadius: size * 0.28,
      border: `2px solid ${TOKENS.ink}`,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      boxShadow: `4px 4px 0 ${TOKENS.ink}`,
    }}>
      <ToolMark tool={tool} size={size * 0.55}/>
    </div>
  );
}

// Abstract tool marks (original, not the actual brand marks)
function ToolMark({ tool, size = 36, color = TOKENS.ink }) {
  if (tool === 'camera') {
    return (
      <svg width={size} height={size} viewBox="0 0 40 40" fill="none">
        <rect x="5" y="11" width="30" height="22" rx="3" stroke={color} strokeWidth="2.5"/>
        <rect x="14" y="7" width="12" height="6" rx="1" stroke={color} strokeWidth="2.5" fill="none"/>
        <circle cx="20" cy="22" r="6" stroke={color} strokeWidth="2.5"/>
        <circle cx="30" cy="15" r="1.5" fill={color}/>
      </svg>
    );
  }
  if (tool === 'chatgpt') {
    // Abstract chat-bubble spark
    return (
      <svg width={size} height={size} viewBox="0 0 40 40" fill="none">
        <path d="M8 10 h18 a6 6 0 0 1 6 6 v8 a6 6 0 0 1 -6 6 h-10 l-8 6 v-6 h0 a6 6 0 0 1 -6 -6 v-8 a6 6 0 0 1 6 -6 z"
              stroke={color} strokeWidth="2.5" strokeLinejoin="round" fill="none"/>
        <path d="M20 15 l2 4 l4 1 l-4 1 l-2 4 l-2 -4 l-4 -1 l4 -1 z" fill={color}/>
      </svg>
    );
  }
  if (tool === 'banana') {
    // Banana silhouette
    return (
      <svg width={size} height={size} viewBox="0 0 40 40" fill="none">
        <path d="M8 12 Q 10 28 22 32 Q 32 34 34 26 Q 30 28 24 26 Q 16 22 14 10 Q 10 10 8 12 Z"
              fill={color} stroke={color} strokeWidth="1.5" strokeLinejoin="round"/>
      </svg>
    );
  }
  if (tool === 'kling') {
    // Play triangle in circle
    return (
      <svg width={size} height={size} viewBox="0 0 40 40" fill="none">
        <circle cx="20" cy="20" r="14" stroke={color} strokeWidth="2.5"/>
        <path d="M17 14 L 27 20 L 17 26 Z" fill={color}/>
      </svg>
    );
  }
  return null;
}

// Rounded card — used as step card, tool card, etc.
function Card({ x, y, width, height, bg, children, rotate = 0, shadow = true, border = true, radius = 18, style }) {
  return (
    <div style={{
      position: 'absolute',
      left: x, top: y, width, height,
      background: bg,
      borderRadius: radius,
      border: border ? `2.5px solid ${TOKENS.ink}` : 'none',
      boxShadow: shadow ? `6px 6px 0 ${TOKENS.ink}` : 'none',
      transform: `rotate(${rotate}deg)`,
      ...style,
    }}>
      {children}
    </div>
  );
}

Object.assign(window, { TOKENS, Sfx, useSfxTimeline, Silhouette, ToolBadge, ToolMark, Card });
