/* Shared utility components and helpers — exposed on window */
const { useState, useEffect, useRef, useMemo, useCallback } = React;

// ===== Lucide icons (mini SVG set, 1.5px stroke) =====
const Icon = ({ name, size = 18, className = "", color }) => {
  const paths = {
    'arrow-right': <path d="M5 12h14M13 5l7 7-7 7" />,
    'arrow-up-right': <path d="M7 17 17 7M7 7h10v10" />,
    'arrow-up': <path d="M12 19V5M5 12l7-7 7 7" />,
    'arrow-down': <path d="M12 5v14M5 12l7 7 7-7" />,
    'sparkles': <><path d="M12 3l1.7 4.6L18 9l-4.3 1.4L12 15l-1.7-4.6L6 9l4.3-1.4L12 3z" /><path d="M19 14l.7 1.9L21 17l-1.3.6L19 19l-.7-1.4L17 17l1.3-1.1L19 14z" /></>,
    'zap': <path d="M13 2 4 14h7l-1 8 9-12h-7l1-8z" />,
    'play': <polygon points="6 4 20 12 6 20" />,
    'pause': <><rect x="6" y="4" width="4" height="16" /><rect x="14" y="4" width="4" height="16" /></>,
    'send': <path d="M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z" />,
    'mic': <><rect x="9" y="2" width="6" height="12" rx="3" /><path d="M19 10a7 7 0 0 1-14 0M12 19v3" /></>,
    'x': <path d="M18 6 6 18M6 6l12 12" />,
    'check': <path d="M20 6 9 17l-5-5" />,
    'plus': <path d="M12 5v14M5 12h14" />,
    'minus': <path d="M5 12h14" />,
    'search': <><circle cx="11" cy="11" r="7" /><path d="m20 20-3.5-3.5" /></>,
    'filter': <path d="M3 4h18M6 12h12M10 20h4" />,
    'calendar': <><rect x="3" y="5" width="18" height="16" rx="2" /><path d="M3 9h18M8 3v4M16 3v4" /></>,
    'map-pin': <><path d="M12 22s7-7 7-12a7 7 0 1 0-14 0c0 5 7 12 7 12z" /><circle cx="12" cy="10" r="3" /></>,
    'users': <><circle cx="9" cy="8" r="4" /><path d="M2 21c0-3.5 3.5-6 7-6s7 2.5 7 6M16 8a4 4 0 0 1 0 8M22 21c0-3-2-5-5-6" /></>,
    'home': <path d="M3 11l9-8 9 8v10a1 1 0 0 1-1 1h-5v-7H9v7H4a1 1 0 0 1-1-1V11z" />,
    'layout-dashboard': <><rect x="3" y="3" width="7" height="9" rx="1" /><rect x="14" y="3" width="7" height="5" rx="1" /><rect x="14" y="12" width="7" height="9" rx="1" /><rect x="3" y="16" width="7" height="5" rx="1" /></>,
    'newspaper': <><path d="M4 4h14a2 2 0 0 1 2 2v13a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V4z" /><path d="M20 8h2v9a2 2 0 0 1-2 2M8 8h6M8 12h6M8 16h4" /></>,
    'bell': <><path d="M6 8a6 6 0 1 1 12 0c0 6 3 8 3 8H3s3-2 3-8" /><path d="M10 20a2 2 0 0 0 4 0" /></>,
    'trophy': <><path d="M6 4h12v3a6 6 0 1 1-12 0V4z" /><path d="M6 7H3v2a3 3 0 0 0 3 3M18 7h3v2a3 3 0 0 1-3 3M9 17h6l1 4H8l1-4z" /></>,
    'flame': <path d="M12 2c1 4-3 4-3 8a5 5 0 0 0 5 5 5 5 0 0 0 5-5c0-3-2-5-2-7-2 1-3 3-5 4 0-2 1-3 0-5z" />,
    'target': <><circle cx="12" cy="12" r="9" /><circle cx="12" cy="12" r="5" /><circle cx="12" cy="12" r="1" /></>,
    'chart-line': <path d="M3 3v18h18M7 14l4-4 4 4 5-6" />,
    'chart-bar': <><path d="M3 3v18h18" /><rect x="7" y="11" width="3" height="6" /><rect x="13" y="7" width="3" height="10" /><rect x="19" y="13" width="0" height="4" /></>,
    'chart-area': <path d="M3 3v18h18M3 17l5-5 4 3 5-7 4 5" />,
    'eye': <><path d="M2 12s4-8 10-8 10 8 10 8-4 8-10 8S2 12 2 12z" /><circle cx="12" cy="12" r="3" /></>,
    'eye-off': <><path d="M3 3l18 18M10.5 6.5A10 10 0 0 1 12 4c6 0 10 8 10 8a18 18 0 0 1-2.6 3.5M6.6 6.6A18 18 0 0 0 2 12s4 8 10 8a10 10 0 0 0 4-1" /></>,
    'download': <><path d="M12 3v14M6 13l6 6 6-6" /><rect x="3" y="20" width="18" height="2" rx="1" /></>,
    'share': <><circle cx="6" cy="12" r="3" /><circle cx="18" cy="6" r="3" /><circle cx="18" cy="18" r="3" /><path d="M9 11l6-3M9 13l6 3" /></>,
    'refresh': <><path d="M21 12a9 9 0 1 1-3-6.7L21 8" /><path d="M21 3v5h-5" /></>,
    'menu': <path d="M3 6h18M3 12h18M3 18h18" />,
    'chevron-down': <path d="M6 9l6 6 6-6" />,
    'chevron-right': <path d="M9 6l6 6-6 6" />,
    'chevron-left': <path d="M15 6l-6 6 6 6" />,
    'star': <path d="M12 2l3 7 8 1-6 5 2 8-7-4-7 4 2-8-6-5 8-1 3-7z" />,
    'shield': <path d="M12 2l8 3v6c0 5-3 9-8 11-5-2-8-6-8-11V5l8-3z" />,
    'shield-check': <><path d="M12 2l8 3v6c0 5-3 9-8 11-5-2-8-6-8-11V5l8-3z" /><path d="M9 12l2 2 4-4" /></>,
    'sticky-note': <><rect x="4" y="4" width="14" height="16" rx="2" /><path d="M14 18l5-5h-5z" /></>,
    'briefcase': <><rect x="3" y="7" width="18" height="13" rx="2" /><path d="M9 7V5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2M3 13h18" /></>,
    'package': <><path d="M3 7l9-4 9 4-9 4-9-4z" /><path d="M3 7v10l9 4 9-4V7" /><path d="M12 11v10" /></>,
    'compass': <><circle cx="12" cy="12" r="10" /><polygon points="16 8 14 14 8 16 10 10" /></>,
    'message-square': <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v10z" />,
    'volume-2': <><path d="M11 5 6 9H2v6h4l5 4V5z" /><path d="M19 12a4 4 0 0 1-1 2.6M22 12a8 8 0 0 1-2 5" /></>,
    'volume-x': <><path d="M11 5 6 9H2v6h4l5 4V5z" /><path d="M22 9l-5 5M17 9l5 5" /></>,
    'lightbulb': <><path d="M9 18h6M10 22h4M9 14a4 4 0 1 1 6 0c-1 1-1 2-1 3H10c0-1 0-2-1-3z" /></>,
    'globe': <><circle cx="12" cy="12" r="10" /><path d="M2 12h20M12 2a15 15 0 0 1 0 20 15 15 0 0 1 0-20z" /></>,
    'rocket': <><path d="M5 19c-2 0-2 0-2 0s0-3 2-5l3 3c-2 2-3 2-3 2zM12 4c5 0 8 3 8 8 0 0-2 1-4 3l-7-7c2-2 3-4 3-4z" /><circle cx="14" cy="10" r="1.5" /></>,
    'check-circle': <><circle cx="12" cy="12" r="10" /><path d="m9 12 2 2 4-4" /></>,
    'alert-circle': <><circle cx="12" cy="12" r="10" /><path d="M12 8v4M12 16h.01" /></>,
    'qr-code': <><rect x="3" y="3" width="7" height="7" /><rect x="14" y="3" width="7" height="7" /><rect x="3" y="14" width="7" height="7" /><path d="M14 14h3v3h-3zM18 18h3v3h-3z" /></>,
    'mail': <><rect x="2" y="4" width="20" height="16" rx="2" /><path d="M2 6l10 7 10-7" /></>,
    'linkedin': <><rect x="3" y="3" width="18" height="18" rx="2" /><path d="M8 10v8M8 7v.01M12 18v-5a3 3 0 0 1 6 0v5" /></>,
    'youtube': <><rect x="2" y="6" width="20" height="12" rx="3" /><polygon points="10 9 16 12 10 15" /></>,
    'twitter': <path d="M22 5a8 8 0 0 1-2.4 1 4 4 0 0 0-7 3.6A11 11 0 0 1 3 4s-4 9 5 13a12 12 0 0 1-7 2c9 5 20 0 20-11.5 0-.3 0-.5-.1-.8A8 8 0 0 0 22 5z" />,
    'instagram': <><rect x="3" y="3" width="18" height="18" rx="5" /><circle cx="12" cy="12" r="4" /><circle cx="17.5" cy="6.5" r=".5" fill="currentColor" /></>,
    'meta': <path d="M3 12c0-5 3-8 6-8 4 0 6 4 9 8 3-4 5-8 9-8 3 0 6 3 6 8 0 5-3 8-6 8-4 0-6-4-9-8-3 4-5 8-9 8-3 0-6-3-6-8z" />,
    'lock': <><rect x="4" y="11" width="16" height="10" rx="2" /><path d="M8 11V7a4 4 0 1 1 8 0v4" /></>,
    'sliders': <><path d="M4 21v-7M4 10V3M12 21v-9M12 8V3M20 21v-5M20 12V3M1 14h6M9 8h6M17 16h6" /></>,
    'arrow-up-down': <path d="M11 4 7 8M7 4v16M17 20l-4-4M17 4v16" />,
    'circle-dot': <><circle cx="12" cy="12" r="9" /><circle cx="12" cy="12" r="3" fill="currentColor" /></>,
    'gift': <><rect x="3" y="8" width="18" height="13" rx="1" /><path d="M3 12h18M12 8v13M8 8c-2 0-3-1-3-2.5S6 3 7.5 3 12 5 12 8c0-3 3-5 4.5-5S20 4 19 5.5 17 8 16 8" /></>,
    'crown': <path d="M2 17l3-9 5 6 2-9 2 9 5-6 3 9z" />,
    'medal': <><circle cx="12" cy="14" r="6" /><path d="M8 14L4 4h4l4 6M16 14l4-10h-4l-4 6" /></>,
    'flag': <><path d="M4 21V4M4 4h11l-2 4 2 4H4" /></>,
    'lightning': <path d="M13 2 4 14h7l-1 8 9-12h-7l1-8z" />,
    'note': <path d="M5 4h11l4 4v12a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1z" />,
    'cube': <path d="M21 7L12 2 3 7v10l9 5 9-5V7zM3 7l9 5 9-5M12 12v10" />,
    'heart': <path d="M12 21s-7-4.5-9-9c-1-2.5 0-6 3.5-6 2 0 3.5 1 4.5 2.5 1-1.5 2.5-2.5 4.5-2.5 3.5 0 4.5 3.5 3.5 6-2 4.5-7 9-7 9z" />,
    'message': <path d="M21 12a8 8 0 0 1-8 8c-1.5 0-3-.4-4.2-1L3 21l1.5-4.5A8 8 0 1 1 21 12z" />,
    'bookmark': <path d="M5 3h14v18l-7-4-7 4V3z" />,
    'clock': <><circle cx="12" cy="12" r="9" /><path d="M12 7v5l3 2" /></>,
    'rotate-ccw': <><path d="M3 12a9 9 0 1 0 3-6.7L3 8" /><path d="M3 3v5h5" /></>,
    'message-circle': <path d="M21 12a9 9 0 0 1-9 9c-1.5 0-3-.4-4.2-1L3 21l1-4.8A9 9 0 1 1 21 12z" />,
    'phone': <path d="M22 16.9v3a2 2 0 0 1-2.2 2 19.8 19.8 0 0 1-8.6-3.1 19.5 19.5 0 0 1-6-6A19.8 19.8 0 0 1 2.1 4.2 2 2 0 0 1 4 2h3.1a2 2 0 0 1 2 1.7l.5 2.8a2 2 0 0 1-.5 1.9L7.6 9.9a16 16 0 0 0 6 6l1.5-1.5a2 2 0 0 1 1.9-.5l2.8.5a2 2 0 0 1 1.7 2z" />,
  };
  const p = paths[name] || <path d="" />;
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color || 'currentColor'} strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" className={className} aria-hidden>
      {p}
    </svg>
  );
};

// ===== Brand =====
const Brand = ({ onClick }) => (
  <a className="brand" onClick={(e) => { e.preventDefault(); onClick && onClick(); }}>
    <img src="assets/symbol-tight.png" alt="Marcianus" />
    <span className="brand-wm">Marcianus <em>Experience.</em></span>
  </a>
);

// ===== Sound effects (synth via WebAudio) =====
const SoundFX = (() => {
  let ctx = null;
  let muted = (typeof localStorage !== 'undefined' && localStorage.getItem('mds-muted') === '1');
  const ensure = () => { if (!ctx && typeof AudioContext !== 'undefined') ctx = new (window.AudioContext || window.webkitAudioContext)(); return ctx; };
  const blip = (freq = 880, dur = 0.07, type = 'sine', vol = 0.04) => {
    if (muted) return;
    const c = ensure(); if (!c) return;
    const o = c.createOscillator(); const g = c.createGain();
    o.type = type; o.frequency.value = freq;
    g.gain.value = 0;
    g.gain.linearRampToValueAtTime(vol, c.currentTime + 0.01);
    g.gain.linearRampToValueAtTime(0, c.currentTime + dur);
    o.connect(g); g.connect(c.destination);
    o.start(); o.stop(c.currentTime + dur);
  };
  const chime = (notes = [880, 1320]) => { notes.forEach((f, i) => setTimeout(() => blip(f, 0.12, 'sine', 0.05), i * 80)); };
  return {
    tap: () => blip(660, 0.05, 'sine', 0.03),
    success: () => chime([880, 1175, 1567]),
    notify: () => chime([1320, 880]),
    levelUp: () => chime([523, 659, 783, 1046]),
    error: () => blip(220, 0.12, 'sawtooth', 0.04),
    setMuted: (v) => { muted = v; try { localStorage.setItem('mds-muted', v ? '1' : '0'); } catch (e) {} },
    isMuted: () => muted,
  };
})();

// ===== Confetti =====
const fireConfetti = (origin = { x: window.innerWidth / 2, y: window.innerHeight / 2 }, colors = ['#FFD700', '#7B61FF', '#00D1FF', '#00C48C']) => {
  const host = document.createElement('div');
  host.className = 'confetti-host';
  host.style.left = origin.x + 'px';
  host.style.top = origin.y + 'px';
  document.body.appendChild(host);
  for (let i = 0; i < 24; i++) {
    const p = document.createElement('div');
    p.className = 'confetti-piece';
    const angle = (Math.PI * 2 * i) / 24 + Math.random() * 0.4;
    const dist = 60 + Math.random() * 80;
    p.style.background = colors[i % colors.length];
    p.style.transform = `translate(${Math.cos(angle) * dist}px, ${Math.sin(angle) * dist}px)`;
    p.style.left = '0';
    p.style.top = '0';
    p.style.animationDelay = (Math.random() * 0.1) + 's';
    host.appendChild(p);
  }
  setTimeout(() => host.remove(), 1600);
};

// ===== Toast manager =====
const ToastBus = (() => {
  const subs = new Set();
  let id = 0;
  return {
    push(t) { id++; const item = { id, ...t }; subs.forEach(fn => fn({ type: 'add', item })); setTimeout(() => subs.forEach(fn => fn({ type: 'remove', id: item.id })), t.duration || 4500); },
    subscribe(fn) { subs.add(fn); return () => subs.delete(fn); },
  };
})();

const ToastHost = () => {
  const [items, setItems] = useState([]);
  useEffect(() => ToastBus.subscribe((ev) => {
    if (ev.type === 'add') setItems(prev => [...prev, ev.item]);
    if (ev.type === 'remove') setItems(prev => prev.filter(p => p.id !== ev.id));
  }), []);
  return (
    <div className="toast-host">
      {items.map(t => (
        <div key={t.id} className={`toast ${t.kind || ''}`} role="status">
          <div className="ic"><Icon name={t.icon || 'sparkles'} size={18} /></div>
          <div className="body">
            <div className="t">{t.title}</div>
            {t.desc && <div className="d">{t.desc}</div>}
          </div>
          <div className="x" onClick={() => setItems(prev => prev.filter(p => p.id !== t.id))}><Icon name="x" size={16} /></div>
        </div>
      ))}
    </div>
  );
};

// ===== Animated number =====
const AnimNum = ({ value, prefix = '', suffix = '', duration = 800, decimals = 0 }) => {
  const [v, setV] = useState(value);
  const ref = useRef(value);
  useEffect(() => {
    const start = ref.current; const end = value; const t0 = performance.now();
    let raf;
    const step = (t) => {
      const k = Math.min(1, (t - t0) / duration);
      const e = 1 - Math.pow(1 - k, 3);
      const cur = start + (end - start) * e;
      setV(cur);
      if (k < 1) raf = requestAnimationFrame(step); else ref.current = end;
    };
    raf = requestAnimationFrame(step);
    return () => cancelAnimationFrame(raf);
  }, [value, duration]);
  const display = decimals ? v.toFixed(decimals) : Math.round(v).toLocaleString('pt-PT');
  return <>{prefix}{display}{suffix}</>;
};

// ===== Sparkline SVG =====
const Sparkline = ({ data, color = '#A78BFA', height = 24, fill = true }) => {
  const max = Math.max(...data); const min = Math.min(...data);
  const range = max - min || 1;
  const w = 100; const h = height;
  const pts = data.map((d, i) => {
    const x = (i / (data.length - 1)) * w;
    const y = h - ((d - min) / range) * (h - 2) - 1;
    return `${x},${y}`;
  });
  const path = `M ${pts.join(' L ')}`;
  const area = `${path} L ${w},${h} L 0,${h} Z`;
  return (
    <svg viewBox={`0 0 ${w} ${h}`} preserveAspectRatio="none" style={{ width: '100%', height }}>
      {fill && <path d={area} fill={color} opacity="0.18" />}
      <path d={path} fill="none" stroke={color} strokeWidth="1.6" strokeLinejoin="round" strokeLinecap="round" />
    </svg>
  );
};

// ===== expose =====
Object.assign(window, { Icon, Brand, SoundFX, fireConfetti, ToastBus, ToastHost, AnimNum, Sparkline });
