/* ============================================================
   Glafia Dex — UI primitives & scaling
   Exports: Badge, StatSeg, Scaler, formatQty, slug
============================================================ */

/* ---------- quantity scaling ---------- */
function niceFrac(n){
  let whole = Math.floor(n);
  const f = n - whole;
  let fr = '';
  if (f >= 0.88) whole += 1;
  else if (f >= 0.63) fr = '¾';
  else if (f >= 0.38) fr = '½';
  else if (f >= 0.13) fr = '¼';
  if (whole === 0 && fr === '') return '0';
  return (whole > 0 ? whole : '') + fr;
}
function roundMetric(n){
  if (n >= 100) return Math.round(n / 10) * 10;
  if (n >= 20)  return Math.round(n / 5) * 5;
  return Math.max(1, Math.round(n));
}
function formatQty(ing, servings, base){
  const ratio = servings / base;
  const v = (ing.qty || 0) * ratio;
  const u = ing.unit || '';
  if (!ing.qty) return u || '';
  if (u === 'g' || u === 'ml') return roundMetric(v) + ' ' + u;
  if (u === 'tbsp' || u === 'tsp') return niceFrac(Math.max(0.5, Math.round(v * 2) / 2)) + ' ' + u;
  const r = Math.max(0.5, Math.round(v * 2) / 2);
  return niceFrac(r) + (u ? ' ' + u : '');
}

function slug(s){ return (s || '').toLowerCase().trim().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, ''); }

/* ---------- box badge (embossed) ---------- */
function Badge({ emoji, label, color, onRemove, faded }){
  return (
    <span className="typebadge" style={{ background: faded ? '#cdc4b0' : color }}>
      <span className="tb-ic">{emoji}</span>{label}
      {onRemove && <button className="tb-x" onClick={(e) => { e.stopPropagation(); onRemove(); }} aria-label={'remove ' + label}>✕</button>}
    </span>
  );
}

/* ---------- stat segments ---------- */
function StatSeg({ value, max = 5, spice }){
  return (
    <span className="seg">
      {Array.from({ length: max }, (_, i) => (
        <i key={i} className={(i < value ? 'on' : '') + (spice ? ' spice' : '')}></i>
      ))}
    </span>
  );
}

/* ---------- serving scaler ---------- */
function Scaler({ servings, onChange, min = 1, max = 24 }){
  return (
    <div className="scaler">
      <button onClick={() => onChange(Math.max(min, servings - 1))} disabled={servings <= min} aria-label="fewer">–</button>
      <span className="val"><b>{servings}</b><small>{servings === 1 ? 'serving' : 'servings'}</small></span>
      <button onClick={() => onChange(Math.min(max, servings + 1))} disabled={servings >= max} aria-label="more">+</button>
    </div>
  );
}

Object.assign(window, { Badge, StatSeg, Scaler, formatQty, slug });

/* ---------- responsive hook ---------- */
function useIsMobile(bp = 880){
  const [m, setM] = React.useState(() => window.matchMedia(`(max-width:${bp}px)`).matches);
  React.useEffect(() => {
    const mq = window.matchMedia(`(max-width:${bp}px)`);
    const h = e => setM(e.matches);
    mq.addEventListener('change', h);
    return () => mq.removeEventListener('change', h);
  }, [bp]);
  return m;
}
Object.assign(window, { useIsMobile });
