/* fx.jsx — sound engine, confetti, abstract thumbnails. Exported to window. */

/* ============ SOUND ============ */
let _ac = null;
const sfx = {
  muted: false,
  ctx() {
    if (!_ac) { try { _ac = new (window.AudioContext || window.webkitAudioContext)(); } catch(e){} }
    if (_ac && _ac.state === "suspended") _ac.resume();
    return _ac;
  },
  tone(freq, t0, dur, type = "sine", gain = 0.18, slide = null) {
    const ac = this.ctx(); if (!ac) return;
    const o = ac.createOscillator(), g = ac.createGain();
    o.type = type; o.frequency.setValueAtTime(freq, t0);
    if (slide) o.frequency.exponentialRampToValueAtTime(slide, t0 + dur);
    g.gain.setValueAtTime(0.0001, t0);
    g.gain.exponentialRampToValueAtTime(gain, t0 + 0.012);
    g.gain.exponentialRampToValueAtTime(0.0001, t0 + dur);
    o.connect(g); g.connect(ac.destination);
    o.start(t0); o.stop(t0 + dur + 0.02);
  },
  play(name) {
    if (this.muted) return;
    const ac = this.ctx(); if (!ac) return;
    const n = ac.currentTime;
    if (name === "complete") {
      [523.25, 659.25, 783.99, 1046.5].forEach((f, i) => this.tone(f, n + i*0.075, 0.28, "triangle", 0.16));
      this.tone(1318.5, n + 0.30, 0.5, "sine", 0.08);
    } else if (name === "levelup") {
      [523.25, 698.46, 880, 1174.7, 1567.98].forEach((f,i)=>this.tone(f, n+i*0.09, 0.4, "sawtooth", 0.10));
      this.tone(2093, n+0.5, 0.6, "sine", 0.06);
    } else if (name === "check") {
      this.tone(880, n, 0.09, "square", 0.07, 1320);
    } else if (name === "uncheck") {
      this.tone(440, n, 0.09, "square", 0.05, 300);
    } else if (name === "drop") {
      this.tone(160, n, 0.12, "sine", 0.14, 90);
      this.tone(320, n, 0.06, "triangle", 0.05);
    } else if (name === "pick") {
      this.tone(420, n, 0.05, "sine", 0.05, 560);
    } else if (name === "click") {
      this.tone(660, n, 0.04, "sine", 0.04);
    } else if (name === "move") {
      this.tone(523, n, 0.07, "triangle", 0.06, 660);
    }
  },
};

/* ============ CONFETTI ============ */
let _cv = null, _cx = null, _parts = [], _raf = null;
function ensureCanvas() {
  if (_cv) return;
  _cv = document.createElement("canvas");
  _cv.className = "confetti-canvas";
  document.body.appendChild(_cv);
  _cx = _cv.getContext("2d");
  const resize = () => { _cv.width = innerWidth * devicePixelRatio; _cv.height = innerHeight * devicePixelRatio;
    _cv.style.width = innerWidth+"px"; _cv.style.height = innerHeight+"px"; _cx.setTransform(devicePixelRatio,0,0,devicePixelRatio,0,0); };
  resize(); addEventListener("resize", resize);
}
function tick() {
  _cx.clearRect(0, 0, innerWidth, innerHeight);
  _parts = _parts.filter(p => p.life > 0);
  for (const p of _parts) {
    p.vy += 0.16; p.x += p.vx; p.y += p.vy; p.vx *= 0.99;
    p.rot += p.vr; p.life -= 1;
    _cx.save(); _cx.translate(p.x, p.y); _cx.rotate(p.rot);
    _cx.globalAlpha = Math.min(1, p.life / 22);
    _cx.fillStyle = p.color;
    if (p.shape === 0) _cx.fillRect(-p.s/2, -p.s/2, p.s, p.s*0.5);
    else { _cx.beginPath(); _cx.arc(0,0,p.s/2,0,7); _cx.fill(); }
    _cx.restore();
  }
  if (_parts.length) _raf = requestAnimationFrame(tick);
  else { _raf = null; _cx.clearRect(0,0,innerWidth,innerHeight); }
}
function fireConfetti(x, y, opts = {}) {
  ensureCanvas();
  const accent = getComputedStyle(document.documentElement).getPropertyValue("--accent").trim() || "#ff7a00";
  const colors = opts.colors || [accent, "#ff9633", "#f5b942", "#ffffff", "#ffd28a"];
  const n = opts.count || 90;
  const spread = opts.spread || 1;
  for (let i = 0; i < n; i++) {
    const a = (Math.random() * Math.PI * 2);
    const sp = (4 + Math.random() * 9) * spread;
    _parts.push({
      x, y, vx: Math.cos(a) * sp, vy: Math.sin(a) * sp - (opts.up ? 6 : 3),
      s: 5 + Math.random() * 7, color: colors[(Math.random()*colors.length)|0],
      rot: Math.random()*7, vr: (Math.random()-0.5)*0.4,
      life: 70 + Math.random()*45, shape: Math.random() < 0.6 ? 0 : 1,
    });
  }
  if (!_raf) _raf = requestAnimationFrame(tick);
}

/* ============ ABSTRACT THUMBNAIL ============ */
/* themed, generated visuals — no stock photos. */
function Thumb({ kind, className }) {
  const styleFor = (k) => {
    const A = "var(--accent)", G = "var(--gold)", P = "var(--c-feature)";
    const M = {
      garagem:    `repeating-linear-gradient(115deg, #161616 0 22px, #1c1c1c 22px 44px), radial-gradient(60% 90% at 30% 110%, rgba(var(--accent-rgb),0.4), transparent 60%)`,
      inventario: `linear-gradient(0deg, rgba(0,0,0,0.4), transparent), repeating-conic-gradient(from 0deg at 50% 50%, #1a1a1a 0 25%, #161616 0 50%)`,
      veiculo:    `radial-gradient(80% 120% at 70% 20%, rgba(var(--accent-rgb),0.45), transparent 55%), linear-gradient(160deg, #0e0e14, #1a1320)`,
      mdt:        `linear-gradient(180deg, #10131c, #0a0d14), radial-gradient(50% 60% at 20% 30%, rgba(91,135,255,0.4), transparent)`,
      cnh:        `linear-gradient(135deg, #1e1a12, #14130d), radial-gradient(60% 80% at 80% 20%, rgba(245,185,66,0.45), transparent)`,
      multas:     `linear-gradient(135deg, #1a1212, #120d0d), radial-gradient(60% 80% at 20% 80%, rgba(240,69,58,0.4), transparent)`,
    };
    return M[k] || `radial-gradient(70% 100% at 50% 0%, rgba(var(--accent-rgb),0.3), transparent), linear-gradient(160deg,#161616,#101010)`;
  };
  return (
    <div className={className} style={{ background: styleFor(kind), position: "relative" }}>
      <div style={{ position:"absolute", inset:0, background:
        "radial-gradient(120% 120% at 50% 120%, transparent 60%, rgba(0,0,0,0.5))" }} />
      <svg width="100%" height="100%" viewBox="0 0 200 120" preserveAspectRatio="xMidYMid slice"
        style={{ position:"absolute", inset:0, opacity:0.5 }}>
        <defs>
          <linearGradient id={"tg"+kind} x1="0" y1="0" x2="1" y2="1">
            <stop offset="0" stopColor="rgba(255,255,255,0.10)" />
            <stop offset="1" stopColor="rgba(255,255,255,0)" />
          </linearGradient>
        </defs>
        {kind === "inventario" && [...Array(12)].map((_,i)=>(
          <rect key={i} x={12+(i%4)*46} y={14+((i/4)|0)*34} width="38" height="26" rx="5"
            fill="none" stroke="rgba(255,255,255,0.14)" />
        ))}
        {kind === "mdt" && <>
          <rect x="12" y="14" width="80" height="92" rx="6" fill="rgba(255,255,255,0.05)" stroke="rgba(91,135,255,0.4)"/>
          <rect x="104" y="14" width="84" height="40" rx="6" fill="rgba(255,255,255,0.04)"/>
          <rect x="104" y="62" width="84" height="44" rx="6" fill="rgba(255,255,255,0.04)"/>
        </>}
        {kind === "cnh" && <>
          <rect x="14" y="22" width="172" height="76" rx="10" fill="rgba(255,255,255,0.05)" stroke="rgba(245,185,66,0.4)"/>
          <circle cx="48" cy="60" r="20" fill="rgba(255,255,255,0.08)"/>
          <rect x="150" y="36" width="26" height="26" rx="3" fill="none" stroke="rgba(245,185,66,0.5)"/>
        </>}
        {(kind==="garagem"||kind==="veiculo") && <>
          <rect x="40" y="58" width="120" height="34" rx="14" fill="rgba(0,0,0,0.35)"/>
          <rect x="62" y="44" width="76" height="26" rx="12" fill="rgba(0,0,0,0.4)"/>
          <circle cx="64" cy="92" r="11" fill="#0a0a0a" stroke="rgba(var(--accent-rgb),0.5)"/>
          <circle cx="136" cy="92" r="11" fill="#0a0a0a" stroke="rgba(var(--accent-rgb),0.5)"/>
        </>}
        {kind === "multas" && <>
          <rect x="30" y="20" width="140" height="80" rx="8" fill="rgba(255,255,255,0.05)"/>
          <path d="M44 38h112M44 54h90M44 70h112M44 84h64" stroke="rgba(240,69,58,0.35)" strokeWidth="4" strokeLinecap="round"/>
        </>}
        <rect x="0" y="0" width="200" height="120" fill={"url(#tg"+kind+")"} />
      </svg>
    </div>
  );
}

/* themed self-contained SVG data URL — used as the card cover fallback so the
   slot looks good when empty and the user can drop a real image to override. */
function thumbDataUrl(kind) {
  const tint = { garagem: "#ff7a00", inventario: "#ff9633", veiculo: "#a855f7",
    mdt: "#5b9bff", cnh: "#f5b942", multas: "#f0453a" }[kind] || "#ff7a00";
  const motif = {
    garagem: `<g stroke='${tint}' stroke-opacity='0.8' stroke-width='3' fill='none'><rect x='196' y='54' width='100' height='42' rx='16'/><rect x='214' y='38' width='64' height='28' rx='13'/><circle cx='220' cy='100' r='12'/><circle cx='272' cy='100' r='12'/></g>`,
    inventario: `<g fill='none' stroke='${tint}' stroke-opacity='0.7' stroke-width='3'>${[0,1,2,3,4].map(i=>`<rect x='${150+i*40}' y='50' width='32' height='32' rx='6'/>`).join("")}</g>`,
    veiculo: `<g stroke='${tint}' stroke-opacity='0.8' stroke-width='3' fill='none'><rect x='190' y='54' width='108' height='40' rx='16'/><rect x='212' y='36' width='66' height='28' rx='13'/><circle cx='216' cy='96' r='12'/><circle cx='272' cy='96' r='12'/></g>`,
    mdt: `<g fill='none' stroke='${tint}' stroke-opacity='0.75' stroke-width='3'><rect x='168' y='38' width='62' height='66' rx='8'/><rect x='244' y='38' width='72' height='30' rx='8'/><rect x='244' y='74' width='72' height='30' rx='8'/></g>`,
    cnh: `<g fill='none' stroke='${tint}' stroke-opacity='0.8' stroke-width='3'><rect x='150' y='40' width='180' height='62' rx='12'/><circle cx='186' cy='71' r='18'/><rect x='296' y='52' width='22' height='22' rx='3'/></g>`,
    multas: `<g stroke='${tint}' stroke-opacity='0.7' stroke-width='5' stroke-linecap='round'><path d='M170 50h140M170 71h96M170 92h140'/></g>`,
  }[kind] || "";
  const svg = `<svg xmlns='http://www.w3.org/2000/svg' width='480' height='140' viewBox='0 0 480 140'>`
    + `<defs><radialGradient id='glow' cx='38%' cy='42%' r='70%'>`
    + `<stop offset='0' stop-color='${tint}' stop-opacity='0.85'/>`
    + `<stop offset='0.45' stop-color='${tint}' stop-opacity='0.18'/>`
    + `<stop offset='1' stop-color='${tint}' stop-opacity='0'/></radialGradient></defs>`
    + `<rect width='480' height='140' fill='#0d0d0d'/>`
    + `<rect width='480' height='140' fill='url(#glow)'/>`
    + `<g stroke='#ffffff' stroke-opacity='0.06' stroke-width='1'>`
    + [0,1,2,3,4,5,6,7,8,9].map(i=>`<line x1='${i*60-60}' y1='0' x2='${i*60+40}' y2='140'/>`).join("")
    + `</g>${motif}`
    + `<rect x='0' y='0' width='480' height='70' fill='#ffffff' fill-opacity='0.04'/></svg>`;
  return "data:image/svg+xml," + encodeURIComponent(svg);
}

window.FX = { sfx, fireConfetti, Thumb, thumbDataUrl, readImageFile };

/* ============ IMAGE IMPORT (downscale to keep localStorage sane) ============ */
function readImageFile(file, maxDim, cb) {
  if (!file || !file.type || !file.type.startsWith("image/")) { cb(null); return; }
  const reader = new FileReader();
  reader.onload = () => {
    const img = new Image();
    img.onload = () => {
      const cap = maxDim || 1280;
      const scale = Math.min(1, cap / Math.max(img.width, img.height));
      const w = Math.max(1, Math.round(img.width * scale));
      const h = Math.max(1, Math.round(img.height * scale));
      const cv = document.createElement("canvas"); cv.width = w; cv.height = h;
      cv.getContext("2d").drawImage(img, 0, 0, w, h);
      let url;
      try { url = cv.toDataURL("image/webp", 0.82); if (url.indexOf("data:image/webp") !== 0) throw 0; }
      catch (e) { url = cv.toDataURL("image/jpeg", 0.85); }
      cb(url);
    };
    img.onerror = () => cb(null);
    img.src = reader.result;
  };
  reader.onerror = () => cb(null);
  reader.readAsDataURL(file);
}
