// tc-fx.jsx — "payday" celebration for the Generate PDF button:
// a synthesized cash-register cha-ching + elegant gold dollar signs flying out.

// ── cha-ching (WebAudio, no asset needed) ────────────────────────────────────
// Real cash-register character: a quick lever "cha" then two bright FM bell
// "chings" (inharmonic metallic partials + long shimmer decay).
function playChaChing() {
  const AC = window.AudioContext || window.webkitAudioContext;
  if (!AC) return;
  const ctx = playChaChing._ac || (playChaChing._ac = new AC());
  if (ctx.state === 'suspended') ctx.resume();
  const now = ctx.currentTime;

  const master = ctx.createGain();
  master.gain.value = 0.5;
  const hp = ctx.createBiquadFilter(); hp.type = 'highpass'; hp.frequency.value = 320;
  master.connect(hp).connect(ctx.destination);

  // lever "cha" — short filtered noise clunk
  const dur = 0.045;
  const buf = ctx.createBuffer(1, Math.floor(ctx.sampleRate * dur), ctx.sampleRate);
  const d = buf.getChannelData(0);
  for (let i = 0; i < d.length; i++) d[i] = (Math.random() * 2 - 1) * Math.pow(1 - i / d.length, 2);
  const noise = ctx.createBufferSource(); noise.buffer = buf;
  const bp = ctx.createBiquadFilter(); bp.type = 'bandpass'; bp.frequency.value = 1900; bp.Q.value = 0.8;
  const ng = ctx.createGain(); ng.gain.value = 0.5;
  noise.connect(bp).connect(ng).connect(master); noise.start(now);

  // FM bell — classic metallic register ding
  const bell = (t0, fc, vol, dur) => {
    const car = ctx.createOscillator(); car.type = 'sine'; car.frequency.value = fc;
    const mod = ctx.createOscillator(); mod.type = 'sine'; mod.frequency.value = fc * 1.41; // inharmonic → metallic
    const mg = ctx.createGain();
    mg.gain.setValueAtTime(fc * 1.4, t0);                       // bright strike
    mg.gain.exponentialRampToValueAtTime(fc * 0.12, t0 + dur * 0.6); // mellows into a ring
    mod.connect(mg); mg.connect(car.frequency);
    const amp = ctx.createGain();
    amp.gain.setValueAtTime(0, t0);
    amp.gain.linearRampToValueAtTime(vol, t0 + 0.003);
    amp.gain.exponentialRampToValueAtTime(0.0004, t0 + dur);
    car.connect(amp); amp.connect(master);
    mod.start(t0); car.start(t0); mod.stop(t0 + dur); car.stop(t0 + dur);
  };
  bell(now + 0.015, 740, 0.5, 0.5);    // lower first hit
  bell(now + 0.10, 1108, 0.55, 1.15);  // bright ringing "ching"
  bell(now + 0.107, 1664, 0.18, 1.0);  // shimmer partial on top
}

// ── flying dollar signs ──────────────────────────────────────────────────────
function paydayFX(el) {
  // Prefer the real cash-register recording; fall back to the synth only if it's
  // not available yet (e.g. offline on the very first use).
  try {
    if (typeof window.playRealChaChing === 'function') {
      window.playRealChaChing().then(function (played) {
        if (!played) { try { playChaChing(); } catch (e) {} }
      });
    } else {
      playChaChing();
    }
  } catch (e) { try { playChaChing(); } catch (e2) {} }
  if (!el) return;
  const r = el.getBoundingClientRect();
  const cx = r.left + r.width / 2, cy = r.top + r.height / 2;

  const layer = document.createElement('div');
  layer.className = 'fx-layer';
  document.body.appendChild(layer);

  const glow = document.createElement('div');
  glow.className = 'fx-glow';
  glow.style.left = cx + 'px'; glow.style.top = cy + 'px';
  layer.appendChild(glow);

  const N = 18;
  for (let i = 0; i < N; i++) {
    const s = document.createElement('span');
    s.className = 'fx-dollar';
    s.textContent = '$';
    const ang = (i / N) * Math.PI * 2 + (Math.random() - 0.5) * 0.5;  // full ring, jittered
    const dist = 70 + Math.random() * 130;
    const dx = Math.cos(ang) * dist;
    const dy = Math.sin(ang) * dist - (18 + Math.random() * 34); // gentle upward bias
    s.style.left = cx + 'px'; s.style.top = cy + 'px';
    s.style.fontSize = (15 + Math.random() * 24) + 'px';
    s.style.setProperty('--dx', dx.toFixed(1) + 'px');
    s.style.setProperty('--dy', dy.toFixed(1) + 'px');
    s.style.setProperty('--rot', ((Math.random() - 0.5) * 160).toFixed(0) + 'deg');
    s.style.animationDelay = Math.floor(Math.random() * 70) + 'ms';
    if (Math.random() < 0.28) s.style.filter = 'blur(1px)';      // depth
    layer.appendChild(s);
  }
  setTimeout(() => layer.remove(), 1800);
}

// ── sticker pop: big entrance, hold, then shake while fading out ──────────────
function stickerPop(src) {
  // avoid stacking duplicates if clicked repeatedly
  document.querySelectorAll('.sticker-pop').forEach(n => n.remove());
  const img = document.createElement('img');
  img.className = 'sticker-pop';
  img.src = src;
  img.alt = '';
  const reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  if (reduce) img.classList.add('reduced');
  document.body.appendChild(img);
  img.addEventListener('animationend', () => img.remove());
  // safety net in case animationend doesn't fire
  setTimeout(() => img.remove(), 2400);
}

Object.assign(window, { paydayFX, playChaChing, stickerPop });
