/* global React */
/* ===========================================================
   shared atoms — Button, Chip, Sticker, Stamp, MascotFollow,
   CursorTrail, Marquee, etc.
   =========================================================== */
const { useState, useEffect, useRef } = React;

const tbbBtnBase = {
  fontFamily: 'Nunito Sans, system-ui',
  fontWeight: 900,
  letterSpacing: '0.08em',
  textTransform: 'uppercase',
  border: '3px solid var(--tbb-ink)',
  borderRadius: 999,
  cursor: 'pointer',
  display: 'inline-flex',
  alignItems: 'center',
  gap: 8,
  transition: 'transform 180ms var(--bounce), box-shadow 180ms var(--bounce), background 120ms ease, color 120ms ease',
  userSelect: 'none',
  textDecoration: 'none',
  whiteSpace: 'nowrap'
};

function Button({ variant = 'primary', size = 'md', children, as = 'button', href, target, rel, onClick, style: extraStyle, ...rest }) {
  const [hover, setHover] = useState(false);
  const [press, setPress] = useState(false);
  const palettes = {
    primary: { bg: 'var(--tbb-hotpink)', color: 'var(--tbb-paper)', hoverBg: 'var(--tbb-ink)', hoverColor: 'var(--tbb-paper)' },
    secondary: { bg: 'var(--tbb-paper)', color: 'var(--tbb-ink)', hoverBg: 'var(--tbb-ink)', hoverColor: 'var(--tbb-paper)' },
    ink: { bg: 'var(--tbb-ink)', color: 'var(--tbb-paper)', hoverBg: 'var(--tbb-hotpink)', hoverColor: 'var(--tbb-paper)' },
    lime: { bg: 'var(--tbb-lime)', color: 'var(--tbb-ink)', hoverBg: 'var(--tbb-ink)', hoverColor: 'var(--tbb-lime)' },
    butter: { bg: 'var(--tbb-butter)', color: 'var(--tbb-ink)', hoverBg: 'var(--tbb-ink)', hoverColor: 'var(--tbb-butter)' },
    sky: { bg: 'var(--tbb-sky)', color: 'var(--tbb-ink)', hoverBg: 'var(--tbb-ink)', hoverColor: 'var(--tbb-sky)' }
  };
  const p = palettes[variant] || palettes.primary;
  const shadow = press ? '1px 1px 0 0 var(--tbb-ink)' : hover ? '8px 8px 0 0 var(--tbb-ink)' : '4px 4px 0 0 var(--tbb-ink)';
  const offset = press ? 'translate(3px,3px)' : hover ? 'translate(-3px,-3px)' : 'none';
  const sizes = {
    sm: { pad: '9px 16px', fs: 12 },
    md: { pad: '14px 22px', fs: 14 },
    lg: { pad: '18px 30px', fs: 16 },
    xl: { pad: '22px 38px', fs: 18 }
  };
  const sz = sizes[size] || sizes.md;
  const style = {
    ...tbbBtnBase, padding: sz.pad, fontSize: sz.fs,
    background: hover ? p.hoverBg : p.bg, color: hover ? p.hoverColor : p.color,
    boxShadow: shadow, transform: offset,
    ...(extraStyle || {})
  };
  const handlers = {
    onMouseEnter: () => setHover(true),
    onMouseLeave: () => {setHover(false);setPress(false);},
    onMouseDown: () => setPress(true),
    onMouseUp: () => setPress(false),
    onClick,
    style,
    ...rest
  };
  if (as === 'a' || href) return <a href={href} target={target} rel={rel} {...handlers}>{children}</a>;
  return <button {...handlers}>{children}</button>;
}

function Chip({ tone = 'lime', children, rot = 0, sticker = false, size = 'md', style = {} }) {
  const palette = {
    lime: { bg: 'var(--tbb-lime)', fg: 'var(--tbb-ink)' },
    pink: { bg: 'var(--tbb-hotpink)', fg: 'var(--tbb-paper)' },
    sky: { bg: 'var(--tbb-sky)', fg: 'var(--tbb-ink)' },
    cyan: { bg: 'var(--tbb-cyan)', fg: 'var(--tbb-ink)' },
    butter: { bg: 'var(--tbb-butter)', fg: 'var(--tbb-ink)' },
    coral: { bg: 'var(--tbb-coral)', fg: 'var(--tbb-paper)' },
    bubble: { bg: 'var(--tbb-bubblegum)', fg: 'var(--tbb-ink)' },
    ink: { bg: 'var(--tbb-ink)', fg: 'var(--tbb-paper)' },
    paper: { bg: 'var(--tbb-paper)', fg: 'var(--tbb-ink)' },
    teal: { bg: 'var(--tbb-teal)', fg: 'var(--tbb-paper)' }
  }[tone];
  const sizes = {
    sm: { pad: '5px 9px', fs: 10 },
    md: { pad: '7px 12px', fs: 11 },
    lg: { pad: '10px 16px', fs: 13 }
  };
  const sz = sizes[size] || sizes.md;
  return (
    <span style={{
      fontFamily: 'Nunito Sans, system-ui',
      fontWeight: 900, fontSize: sz.fs, letterSpacing: '0.12em',
      textTransform: 'uppercase', padding: sz.pad,
      border: '2.5px solid var(--tbb-ink)', borderRadius: 999,
      display: 'inline-flex', alignItems: 'center', gap: 6,
      background: palette.bg, color: palette.fg,
      transform: rot ? `rotate(${rot}deg)` : undefined,
      boxShadow: sticker ? '3px 3px 0 0 var(--tbb-ink)' : undefined,
      ...style
    }}>{children}</span>);

}

function Stamp({ children, tone = 'butter', rot = -4, style = {} }) {
  const tones = {
    butter: 'var(--tbb-butter)', pink: 'var(--tbb-hotpink)', sky: 'var(--tbb-sky)', lime: 'var(--tbb-lime)', cyan: 'var(--tbb-cyan)', coral: 'var(--tbb-coral)', bubble: 'var(--tbb-bubblegum)'
  };
  return (
    <span className="tbb-stamp" style={{
      background: tones[tone],
      transform: `rotate(${rot}deg)`,
      ...style
    }}>{children}</span>);

}

/* ===== Marquee ===== */
function Marquee({ items, tone = 'ink', rev = false, big = true }) {
  const fg = tone === 'ink' ? 'var(--tbb-paper)' : 'var(--tbb-ink)';
  const bg = { ink: 'var(--tbb-ink)', pink: 'var(--tbb-hotpink)', lime: 'var(--tbb-lime)', butter: 'var(--tbb-butter)', sky: 'var(--tbb-sky)', cyan: 'var(--tbb-cyan)', coral: 'var(--tbb-coral)', paper: 'var(--tbb-paper)' }[tone];
  return (
    <div style={{
      background: bg, color: fg,
      padding: big ? '32px 0 28px' : '20px 0 16px',
      overflow: 'hidden',
      borderTop: '3px solid var(--tbb-ink)',
      borderBottom: '3px solid var(--tbb-ink)', fontFamily: "Olivita"
    }}>
      <div className={`tbb-marquee-track${rev ? ' rev' : ''}`}>
        {Array.from({ length: 3 }).map((_, n) => items.map((it, i) =>
        <span key={`${n}-${i}`} style={{

          fontStyle: 'italic',
          fontSize: big ? 42 : 24,
          lineHeight: 1.25,
          letterSpacing: '-0.01em',
          display: 'inline-flex',
          alignItems: 'center',
          gap: 24, fontFamily: "\"Hiragino Kaku W9\""
        }}>
            {it} <span style={{ opacity: 0.55, fontSize: big ? 28 : 18 }}>✦</span>
          </span>
        ))}
      </div>
    </div>);

}

/* ===== Mascot follow ===== */
function MascotFollow({ src = 'assets/mascot-primary.png', size = 460, blink = true }) {
  const [t, setT] = useState({ x: 0, y: 0, rx: 0, ry: 0 });
  const [eye, setEye] = useState(false);
  const ref = useRef(null);
  useEffect(() => {
    function onMove(e) {
      const el = ref.current;
      if (!el) return;
      const r = el.getBoundingClientRect();
      const cx = r.left + r.width / 2;
      const cy = r.top + r.height / 2;
      const dx = (e.clientX - cx) / (window.innerWidth / 2);
      const dy = (e.clientY - cy) / (window.innerHeight / 2);
      setT({ x: dx * 18, y: dy * 12, rx: -dy * 5, ry: dx * 8 });
    }
    window.addEventListener('mousemove', onMove);
    return () => window.removeEventListener('mousemove', onMove);
  }, []);
  useEffect(() => {
    if (!blink) return;
    const id = setInterval(() => {setEye(true);setTimeout(() => setEye(false), 150);}, 4200);
    return () => clearInterval(id);
  }, [blink]);
  return (
    <div ref={ref} style={{ position: 'relative', display: 'flex', justifyContent: 'center', alignItems: 'center', perspective: 900 }}>
      <img
        src={src}
        alt="Tokyo Bikini Bar mascot"
        style={{
          width: '100%',
          maxWidth: size,
          filter: `drop-shadow(8px 8px 0 var(--tbb-ink)) ${eye ? 'brightness(0.96)' : ''}`,
          transform: `translate3d(${t.x}px, ${t.y}px, 0) rotateX(${t.rx}deg) rotateY(${t.ry}deg)`,
          transition: 'transform 240ms var(--bounce), filter 80ms ease',
          transformStyle: 'preserve-3d',
          willChange: 'transform'
        }} />
      
    </div>);

}

/* ===== Cursor sparkle trail ===== */
function CursorTrail({ enabled = true }) {
  const canvasRef = useRef(null);
  const particlesRef = useRef([]);
  const lastRef = useRef({ x: 0, y: 0, t: 0 });
  useEffect(() => {
    if (!enabled) return;
    const canvas = canvasRef.current;
    const ctx = canvas.getContext('2d');
    let raf;
    function resize() {
      canvas.width = window.innerWidth * devicePixelRatio;
      canvas.height = window.innerHeight * devicePixelRatio;
      canvas.style.width = window.innerWidth + 'px';
      canvas.style.height = window.innerHeight + 'px';
      ctx.setTransform(devicePixelRatio, 0, 0, devicePixelRatio, 0, 0);
    }
    resize();
    window.addEventListener('resize', resize);

    const colors = ['#FF1F6D', '#FF7A45', '#C7E94B', '#2EC5FF', '#F7E26B', '#FF8FBE'];
    const glyphs = ['✦', '✧', '♡', '✿', '★', '✦'];

    function onMove(e) {
      const now = performance.now();
      const dt = now - lastRef.current.t;
      if (dt < 32) return; // throttle
      lastRef.current = { x: e.clientX, y: e.clientY, t: now };
      const n = 1 + (Math.random() < 0.25 ? 1 : 0);
      for (let i = 0; i < n; i++) {
        particlesRef.current.push({
          x: e.clientX + (Math.random() - 0.5) * 12,
          y: e.clientY + (Math.random() - 0.5) * 12,
          vx: (Math.random() - 0.5) * 1.2,
          vy: (Math.random() - 0.5) * 1.2 - 0.4,
          life: 0,
          ttl: 700 + Math.random() * 500,
          color: colors[Math.floor(Math.random() * colors.length)],
          glyph: glyphs[Math.floor(Math.random() * glyphs.length)],
          size: 14 + Math.random() * 14,
          rot: (Math.random() - 0.5) * 60,
          spin: (Math.random() - 0.5) * 2
        });
      }
      if (particlesRef.current.length > 80) {
        particlesRef.current.splice(0, particlesRef.current.length - 80);
      }
    }
    window.addEventListener('mousemove', onMove);
    window.addEventListener('touchmove', (e) => {
      const t = e.touches[0];if (t) onMove({ clientX: t.clientX, clientY: t.clientY });
    }, { passive: true });

    let last = performance.now();
    function loop(now) {
      const dt = now - last;last = now;
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      const ps = particlesRef.current;
      for (let i = ps.length - 1; i >= 0; i--) {
        const p = ps[i];
        p.life += dt;
        if (p.life >= p.ttl) {ps.splice(i, 1);continue;}
        p.x += p.vx;p.y += p.vy;
        p.vy += 0.012; // slight gravity
        p.rot += p.spin;
        const t = 1 - p.life / p.ttl;
        ctx.save();
        ctx.globalAlpha = t;
        ctx.translate(p.x, p.y);
        ctx.rotate(p.rot * Math.PI / 180);
        ctx.font = `900 ${p.size * (0.7 + 0.3 * t)}px "Nunito Sans", system-ui`;
        ctx.textAlign = 'center';ctx.textBaseline = 'middle';
        // ink outline
        ctx.lineWidth = 2.5;
        ctx.strokeStyle = '#0A0A0A';
        ctx.strokeText(p.glyph, 0, 0);
        ctx.fillStyle = p.color;
        ctx.fillText(p.glyph, 0, 0);
        ctx.restore();
      }
      raf = requestAnimationFrame(loop);
    }
    raf = requestAnimationFrame(loop);

    return () => {
      cancelAnimationFrame(raf);
      window.removeEventListener('resize', resize);
      window.removeEventListener('mousemove', onMove);
    };
  }, [enabled]);
  if (!enabled) return null;
  return <canvas id="tbb-cursor-canvas" ref={canvasRef} />;
}

/* ===== Reveal-on-scroll wrapper ===== */
function Reveal({ children, delay = 0, as = 'div', style = {}, className = '', ...rest }) {
  const ref = useRef(null);
  const [shown, setShown] = useState(false);
  useEffect(() => {
    const el = ref.current;if (!el) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting) {setTimeout(() => setShown(true), delay);io.unobserve(el);}
      });
    }, { threshold: 0.12 });
    io.observe(el);
    return () => io.disconnect();
  }, [delay]);
  const Tag = as;
  return <Tag ref={ref} className={`tbb-reveal ${shown ? 'in' : ''} ${className}`} style={style} {...rest}>{children}</Tag>;
}

/* ===== Sticker — a generic chunky outlined card ===== */
function Sticker({ children, tone = 'paper', rot = 0, radius = 28, style = {}, hover = false, ...rest }) {
  const tones = {
    paper: 'var(--tbb-paper)', white: 'var(--tbb-white)', pink: 'var(--tbb-hotpink)',
    lime: 'var(--tbb-lime)', butter: 'var(--tbb-butter)', sky: 'var(--tbb-sky)',
    bubble: 'var(--tbb-bubblegum)', coral: 'var(--tbb-coral)', cyan: 'var(--tbb-cyan)',
    ink: 'var(--tbb-ink)', teal: 'var(--tbb-teal)'
  };
  return (
    <div className={hover ? 'tbb-peel' : ''} style={{
      background: tones[tone],
      color: ['pink', 'coral', 'ink', 'teal'].includes(tone) ? 'var(--tbb-paper)' : 'var(--tbb-ink)',
      border: '3px solid var(--tbb-ink)',
      borderRadius: radius,
      boxShadow: '5px 5px 0 0 var(--tbb-ink)',
      transform: rot ? `rotate(${rot}deg)` : undefined,
      ...style
    }} {...rest}>{children}</div>);

}

Object.assign(window, { Button, Chip, Stamp, Marquee, MascotFollow, CursorTrail, Reveal, Sticker });