// Primitives, icons, hooks for Vivaz landing

const { useState, useEffect, useRef, useCallback } = React;

function Diamond({ size = 12, color = 'var(--orange)' }) {
  return (
    <span
      aria-hidden="true"
      style={{
        display: 'inline-block',
        width: size,
        height: size * 1.7,
        background: color,
        clipPath: 'polygon(50% 0, 100% 50%, 50% 100%, 0 50%)',
        verticalAlign: 'middle',
      }}
    />
  );
}

function Arrow({ size = 16 }) {
  return (
    <svg className="arrow" width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
      <line x1="5" y1="12" x2="19" y2="12" />
      <polyline points="12 5 19 12 12 19" />
    </svg>
  );
}

function Plus({ size = 14 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
      <line x1="12" y1="5" x2="12" y2="19" />
      <line x1="5" y1="12" x2="19" y2="12" />
    </svg>
  );
}

function ChevronLeft({ size = 18 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
      <polyline points="15 18 9 12 15 6" />
    </svg>
  );
}
function ChevronRight({ size = 18 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
      <polyline points="9 18 15 12 9 6" />
    </svg>
  );
}
function WhatsappIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="currentColor">
      <path d="M17.6 6.32A7.85 7.85 0 0 0 12.05 4a7.94 7.94 0 0 0-6.78 12L4 20l4.1-1.08a7.93 7.93 0 0 0 3.94 1h.01a7.95 7.95 0 0 0 5.55-13.6zm-5.55 12.21a6.6 6.6 0 0 1-3.36-.92l-.24-.14-2.43.64.65-2.37-.16-.25a6.6 6.6 0 1 1 12.27-3.5 6.6 6.6 0 0 1-6.73 6.54zm3.62-4.93c-.2-.1-1.17-.58-1.35-.64-.18-.07-.31-.1-.45.1s-.51.64-.63.78c-.11.13-.23.15-.43.05a5.4 5.4 0 0 1-1.6-.99 6 6 0 0 1-1.1-1.38c-.12-.2-.01-.3.09-.4.09-.09.2-.23.3-.35.1-.11.13-.2.2-.34.07-.13.03-.25-.02-.35-.05-.1-.45-1.08-.61-1.48-.16-.39-.33-.34-.45-.34l-.39-.01a.74.74 0 0 0-.54.25 2.24 2.24 0 0 0-.7 1.67 3.9 3.9 0 0 0 .8 2.06 8.9 8.9 0 0 0 3.4 3 11.66 11.66 0 0 0 1.13.42 2.72 2.72 0 0 0 1.25.08c.38-.06 1.17-.48 1.34-.94.16-.46.16-.85.11-.94-.05-.1-.18-.15-.38-.25z" />
    </svg>
  );
}

// hook: detect window scroll, return true when scrolled past threshold
function useScrolled(threshold = 12) {
  const [s, setS] = useState(false);
  useEffect(() => {
    const onScroll = () => setS(window.scrollY > threshold);
    onScroll();
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => window.removeEventListener('scroll', onScroll);
  }, [threshold]);
  return s;
}

// hook: intersection-observer based reveal
function useReveal() {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    el.classList.add('reveal');
    let done = false;
    const show = () => {
      if (done) return;
      done = true;
      el.classList.add('in');
    };
    // Fallback: always show after a short delay even if IO never fires
    const fallback = setTimeout(show, 600);
    let io;
    try {
      io = new IntersectionObserver(
        (entries) => {
          entries.forEach((e) => {
            if (e.isIntersecting) {
              show();
              io && io.unobserve(el);
            }
          });
        },
        { threshold: 0.08, rootMargin: '0px 0px -40px 0px' }
      );
      io.observe(el);
      // If element is already in viewport on mount, IO sometimes fires before next paint — also check synchronously
      requestAnimationFrame(() => {
        const r = el.getBoundingClientRect();
        if (r.top < (window.innerHeight || 800) && r.bottom > 0) show();
      });
    } catch (_) {
      show();
    }
    return () => { clearTimeout(fallback); if (io) io.disconnect(); };
  }, []);
  return ref;
}

function Reveal({ children, as = 'div', delay = 0, style, className }) {
  const ref = useReveal();
  const Tag = as;
  return (
    <Tag ref={ref} className={className} style={{ ...style, transitionDelay: delay + 'ms' }}>
      {children}
    </Tag>
  );
}

// Reveal variant: clip-path wipe (left→right)
function RevealWipe({ children, delay = 0, className }) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    el.style.clipPath = 'inset(0 100% 0 0)';
    el.style.transition = `clip-path 0.85s cubic-bezier(0.16,1,0.3,1) ${delay}ms`;
    let done = false;
    const show = () => {
      if (done) return;
      done = true;
      el.style.clipPath = 'inset(0 0% 0 0)';
    };
    const io = new IntersectionObserver(([e]) => { if (e.isIntersecting) { show(); io.unobserve(el); } }, { threshold: 0.1 });
    io.observe(el);
    requestAnimationFrame(() => {
      const r = el.getBoundingClientRect();
      if (r.top < window.innerHeight) show();
    });
    return () => io.disconnect();
  }, [delay]);
  return <div ref={ref} className={className}>{children}</div>;
}

// Reveal variant: scale up from 0.92
function RevealScale({ children, delay = 0 }) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    el.style.opacity = '0';
    el.style.transform = 'scale(0.92) translateY(16px)';
    el.style.transition = `opacity 0.7s cubic-bezier(0.16,1,0.3,1) ${delay}ms, transform 0.7s cubic-bezier(0.16,1,0.3,1) ${delay}ms`;
    let done = false;
    const show = () => {
      if (done) return; done = true;
      el.style.opacity = '1'; el.style.transform = 'none';
    };
    const io = new IntersectionObserver(([e]) => { if (e.isIntersecting) { show(); io.unobserve(el); } }, { threshold: 0.1 });
    io.observe(el);
    requestAnimationFrame(() => { const r = el.getBoundingClientRect(); if (r.top < window.innerHeight) show(); });
    return () => io.disconnect();
  }, [delay]);
  return <div ref={ref}>{children}</div>;
}

// Animated counter for stat numbers
function CountUp({ value, suffix = '', duration = 1400 }) {
  const [displayed, setDisplayed] = useState('0');
  const ref = useRef(null);
  const started = useRef(false);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver(([e]) => {
      if (e.isIntersecting && !started.current) {
        started.current = true;
        io.unobserve(el);
        const raw = value.replace(/[^0-9]/g, '');
        const prefix = value.match(/^[^0-9]*/)?.[0] || '';
        const target = parseInt(raw, 10);
        if (isNaN(target)) { setDisplayed(value); return; }
        const start = performance.now();
        const tick = (now) => {
          const p = Math.min((now - start) / duration, 1);
          const ease = 1 - Math.pow(1 - p, 4);
          const cur = Math.round(ease * target);
          setDisplayed(prefix + cur + suffix);
          if (p < 1) requestAnimationFrame(tick);
        };
        requestAnimationFrame(tick);
      }
    }, { threshold: 0.2 });
    io.observe(el);
    return () => io.disconnect();
  }, [value, suffix, duration]);
  return <span ref={ref} style={{ fontVariantNumeric: 'tabular-nums' }}>{displayed}</span>;
}

// Parallax wrapper (subtle vertical shift on scroll)
function Parallax({ children, speed = 0.08, className }) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const onScroll = () => {
      const rect = el.getBoundingClientRect();
      const center = rect.top + rect.height / 2 - window.innerHeight / 2;
      el.style.transform = `translateY(${center * speed}px)`;
    };
    window.addEventListener('scroll', onScroll, { passive: true });
    onScroll();
    return () => window.removeEventListener('scroll', onScroll);
  }, [speed]);
  return <div ref={ref} className={className}>{children}</div>;
}

Object.assign(window, {
  Diamond, Arrow, Plus, ChevronLeft, ChevronRight, WhatsappIcon,
  useScrolled, useReveal, Reveal, RevealWipe, RevealScale, CountUp, Parallax,
});
