/* global React */
const { useEffect, useState, useRef } = React;

/* ── Hooks ─────────────────────────────────────────────────── */

// IntersectionObserver — adds .in class when element enters viewport
function useReveal() {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    if (!('IntersectionObserver' in window)) {
      el.classList.add('in');
      return;
    }
    const io = new IntersectionObserver(
      (entries) => {
        entries.forEach((e) => {
          if (e.isIntersecting) {
            e.target.classList.add('in');
            io.unobserve(e.target);
          }
        });
      },
      { threshold: 0.12, rootMargin: '0px 0px -8% 0px' }
    );
    io.observe(el);
    return () => io.disconnect();
  }, []);
  return ref;
}

// Cycle through a list every N ms; returns active index
function useCycle(length, intervalMs = 4500, paused = false) {
  const [i, setI] = useState(0);
  useEffect(() => {
    if (paused) return;
    const id = setInterval(() => setI((x) => (x + 1) % length), intervalMs);
    return () => clearInterval(id);
  }, [length, intervalMs, paused]);
  return [i, setI];
}

// Animate a number from 0 → target over `dur` ms (re-runs when key changes)
function useCountUp(target, dur = 900, key) {
  const [v, setV] = useState(0);
  useEffect(() => {
    let raf, start;
    const from = 0;
    const step = (t) => {
      if (!start) start = t;
      const p = Math.min(1, (t - start) / dur);
      // ease-out cubic
      const eased = 1 - Math.pow(1 - p, 3);
      setV(Math.round(from + (target - from) * eased));
      if (p < 1) raf = requestAnimationFrame(step);
    };
    raf = requestAnimationFrame(step);
    return () => cancelAnimationFrame(raf);
  }, [target, dur, key]);
  return v;
}

/* ── Tiny icon system (lucide-style, inline) ───────────────── */
const Icon = ({ name, size = 16, stroke = 1.6, className = '' }) => {
  const paths = {
    sparkles: <><path d="M5 3v4M3 5h4M19 11v4M17 13h4M11 3l1.8 4.2L17 9l-4.2 1.8L11 15l-1.8-4.2L5 9l4.2-1.8L11 3z"/></>,
    compare:  <><path d="M8 3v18M16 21V3M2 7l6-4M22 17l-6 4"/></>,
    activity: <><path d="M3 12h4l3-9 4 18 3-9h4"/></>,
    arrow:    <><path d="M5 12h14M13 5l7 7-7 7"/></>,
    arrowUp:  <><path d="M7 17L17 7M7 7h10v10"/></>,
    check:    <><path d="M20 6L9 17l-5-5"/></>,
    plus:     <><path d="M12 5v14M5 12h14"/></>,
    minus:    <><path d="M5 12h14"/></>,
    image:    <><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="9" cy="9" r="1.5"/><path d="M21 15l-5-5L5 21"/></>,
    upload:   <><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M17 8l-5-5-5 5M12 3v12"/></>,
    bolt:     <><path d="M13 2L3 14h7l-1 8 10-12h-7l1-8z"/></>,
    eye:      <><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8S1 12 1 12z"/><circle cx="12" cy="12" r="3"/></>,
    heart:    <><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></>,
    chat:     <><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"/></>,
    sun:      <><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></>,
    moon:     <><path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/></>,
    grid:     <><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/></>,
    pdf:      <><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6M9 13h6M9 17h4"/></>,
    target:   <><circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="6"/><circle cx="12" cy="12" r="2"/></>,
    flame:    <><path d="M8.5 14.5A2.5 2.5 0 0 0 11 17c1.4 0 2.5-1.1 2.5-2.5 0-1.5-1-2.5-2-3.5C10 9.5 9 8 9.5 5c-2 1-4 4-4 7.5a6.5 6.5 0 1 0 13 0c0-3-2-5-3.5-7-.5 2-2 4-3 6.5-.5 1-1.5 2-3.5 2.5z"/></>,
    arrowR:   <><path d="M9 18l6-6-6-6"/></>,
    play:     <><path d="M5 3l14 9-14 9V3z"/></>,
    refresh:  <><path d="M23 4v6h-6M1 20v-6h6"/><path d="M3.5 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.65 4.36A9 9 0 0 0 20.5 15"/></>,
    layers:   <><path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/></>,
    shield:   <><path d="M12 2l9 4v6c0 5-4 9-9 10-5-1-9-5-9-10V6l9-4z"/></>,
    zap:      <><path d="M13 2L3 14h7l-1 8 10-12h-7l1-8z"/></>,
    code:     <><path d="M16 18l6-6-6-6M8 6l-6 6 6 6"/></>,
  };
  return (
    <svg
      width={size} height={size} viewBox="0 0 24 24"
      fill="none" stroke="currentColor" strokeWidth={stroke}
      strokeLinecap="round" strokeLinejoin="round"
      className={className} aria-hidden="true"
    >
      {paths[name] || paths.bolt}
    </svg>
  );
};

/* ── Mock dataset (drives hero + demo + previews) ──────────── */
const PRODUCTS = [
  {
    name: 'Buldak Carbonara',
    brand: 'Samyang',
    category: 'Instant Noodle · Asia',
    stage: 'Peak',
    stageHue: '#f59e0b',
    growth: 87, demand: 92, momentum: 78,
    price: '$3.20 / pack',
    summary:
      'Top-shelf TikTok virality crossed into mainstream demand. Reviewers cite creaminess and heat balance; restocks selling out within 48h at US Asian markets.',
    metrics: [
      { label: 'TikTok views (30d)',   value: '1.2B' },
      { label: 'Reddit mentions (7d)', value: '4.1k' },
      { label: 'Search lift YoY',      value: '+312%' },
      { label: 'Retail SKU growth',    value: '+58%' },
    ],
    rivals: ['Shin Ramyun', 'Indomie Mi Goreng', 'Nongshim Chapagetti'],
    trendStage: 'Peak hype → early plateau',
  },
  {
    name: 'Olipop Cherry Cola',
    brand: 'Olipop',
    category: 'Better-for-you Soda',
    stage: 'Hot',
    stageHue: '#ef4444',
    growth: 81, demand: 88, momentum: 84,
    price: '$2.49 / can',
    summary:
      'Gut-health soda category leader. Whole Foods + Target placements driving Q2 lift; new flavor SKU outperforming hero line on social.',
    metrics: [
      { label: 'TikTok views (30d)',   value: '480M' },
      { label: 'Reddit mentions (7d)', value: '2.4k' },
      { label: 'Search lift YoY',      value: '+186%' },
      { label: 'Retail SKU growth',    value: '+44%' },
    ],
    rivals: ['Poppi', 'Health-Ade', 'Culture Pop'],
    trendStage: 'Sustained growth',
  },
  {
    name: 'Labubu Plush',
    brand: 'Pop Mart',
    category: 'Collectible · Asia → Global',
    stage: 'Hot',
    stageHue: '#ef4444',
    growth: 94, demand: 96, momentum: 91,
    price: '$28–$220 (blind box)',
    summary:
      'K-pop adjacent collectible bag charm. Resale prices 6–8x retail in NA/EU. Pop Mart capacity-constrained; secondhand market validates depth of demand.',
    metrics: [
      { label: 'TikTok views (30d)',   value: '3.8B' },
      { label: 'Reddit mentions (7d)', value: '6.3k' },
      { label: 'Search lift YoY',      value: '+1,240%' },
      { label: 'Retail SKU growth',    value: '+92%' },
    ],
    rivals: ['Sonny Angel', 'Smiski', 'Sanrio'],
    trendStage: 'Hyperscale breakout',
  },
  {
    name: 'Stanley Quencher H2.0',
    brand: 'Stanley',
    category: 'Drinkware',
    stage: 'Cooling',
    stageHue: '#3b82f6',
    growth: 41, demand: 62, momentum: 28,
    price: '$45 / unit',
    summary:
      'Past-peak. Search interest down 38% YoY but installed base + brand love sustain a long tail. Color drops still move; core silhouette saturated.',
    metrics: [
      { label: 'TikTok views (30d)',   value: '110M' },
      { label: 'Reddit mentions (7d)', value: '720' },
      { label: 'Search lift YoY',      value: '-38%' },
      { label: 'Retail SKU growth',    value: '+4%' },
    ],
    rivals: ['Owala FreeSip', 'YETI Rambler', 'Hydro Flask'],
    trendStage: 'Declining hype, durable demand',
  },
];

/* Export to window so other Babel scripts can use */
Object.assign(window, { useReveal, useCycle, useCountUp, Icon, PRODUCTS });
