/* Small reusable atoms */

const Placeholder = ({ label, ratio = "16/9", style = {}, radius = 0, children }) => (
  <div className="ph" style={{ aspectRatio: ratio, borderRadius: radius, ...style }}>
    {label ? <span className="ph-label">{label}</span> : null}
    {children}
  </div>
);

const Eyebrow = ({ children, dot = false, color }) => (
  <div className="eyebrow" style={{ display: "inline-flex", alignItems: "center", gap: 8, color: color || "var(--mute)" }}>
    {dot ? <span style={{ width: 8, height: 8, borderRadius: 999, background: color || "var(--orange)" }} /> : null}
    {children}
  </div>
);

const Tag = ({ children, filled = false, dot = false, style = {} }) => (
  <span className={`tag ${filled ? "tag-filled" : ""} ${dot ? "tag-dot" : ""}`} style={style}>
    {children}
  </span>
);

const Btn = ({ kind = "ink", size = "", children, onClick, icon, style = {} }) => (
  <button
    className={`btn btn-${kind} ${size ? `btn-${size}` : ""}`}
    onClick={onClick}
    style={style}
  >
    {children}
    {icon !== null && (icon || <Icon.ArrowRight size={14} />)}
  </button>
);

/* Animated number that counts on mount */
const CountUp = ({ to, suffix = "", duration = 1400, decimals = 0 }) => {
  const [v, setV] = React.useState(0);
  React.useEffect(() => {
    let raf, start;
    const step = (t) => {
      if (!start) start = t;
      const p = Math.min(1, (t - start) / duration);
      const eased = 1 - Math.pow(1 - p, 3);
      setV(to * eased);
      if (p < 1) raf = requestAnimationFrame(step);
    };
    raf = requestAnimationFrame(step);
    return () => cancelAnimationFrame(raf);
  }, [to, duration]);
  return <span>{v.toFixed(decimals).replace(/\B(?=(\d{3})+(?!\d))/g, ",")}{suffix}</span>;
};

/* Reveal on scroll */
const Reveal = ({ children, delay = 0, y = 14, as: As = "div", style = {}, ...rest }) => {
  const ref = React.useRef(null);
  const [shown, setShown] = React.useState(false);
  React.useEffect(() => {
    const el = ref.current;
    if (!el) return;
    // Fallback: if anything blocks the IntersectionObserver (older browsers, hash-route
    // mounts that scroll instantly past the trigger), reveal the element after 1.5s
    // so content never gets stuck at opacity:0.
    const fallback = setTimeout(() => setShown(true), 1500);
    if (typeof IntersectionObserver === "undefined") {
      setShown(true);
      return () => clearTimeout(fallback);
    }
    const io = new IntersectionObserver(
      ([e]) => { if (e.isIntersecting) { setShown(true); io.disconnect(); clearTimeout(fallback); } },
      { threshold: 0.05, rootMargin: "0px 0px -10% 0px" }
    );
    io.observe(el);
    return () => { io.disconnect(); clearTimeout(fallback); };
  }, []);
  return (
    <As
      ref={ref}
      style={{
        opacity: shown ? 1 : 0,
        transform: shown ? "translateY(0)" : `translateY(${y}px)`,
        transition: `opacity 0.7s cubic-bezier(0.22,1,0.36,1) ${delay}ms, transform 0.7s cubic-bezier(0.22,1,0.36,1) ${delay}ms`,
        ...style,
      }}
      {...rest}
    >
      {children}
    </As>
  );
};

/* Marquee */
const Marquee = ({ children, speed = "normal", style = {}, gap = 48, pauseable = true, reverse = false }) => {
  const cls = `marquee ${speed === "fast" ? "marquee-fast" : speed === "slow" ? "marquee-slow" : ""}`;
  return (
    <div style={{ overflow: "hidden", maskImage: "linear-gradient(90deg, transparent, black 8%, black 92%, transparent)", WebkitMaskImage: "linear-gradient(90deg, transparent, black 8%, black 92%, transparent)", ...style }}>
      <div className={cls} style={{ gap, animationDirection: reverse ? "reverse" : "normal" }}>
        <div style={{ display: "flex", gap, alignItems: "center" }}>{children}</div>
        <div style={{ display: "flex", gap, alignItems: "center" }} aria-hidden>{children}</div>
      </div>
    </div>
  );
};

/* Brand metadata — real Tamak retail brands.
   Store counts verified from each brand's site mirror where possible. */
const BRANDS = [
  { key: "adopt",    name: "Adopt",         tagline: "Parfums Français · Made in Bordeaux",         color: "#E8A3B1", ink: "#1A1B17", category: "Beauty",   since: "2013", image: "assets/brands/adopt-hero.jpg",            hero: "assets/brands/adopt-hero.jpg",       stores: 20, imageFit: "cover" },
  { key: "citadel",  name: "Citadel",       tagline: "Feel Great Anywhere · Mauritian lifestyle",   color: "#4DB6AC", ink: "#FFFFFF", category: "Fashion",  since: "1983", image: "assets/brands/citadel-logo.webp",         hero: "assets/brands/citadel-tee-3.png",    stores: 12, imageFit: "contain", imageBg: "#FFFFFF" },
  { key: "funky",    name: "Funky Fish",    tagline: "Trendy accessories & gifts",                  color: "#E91E63", ink: "#FFFFFF", category: "Lifestyle",since: "2008", image: "assets/brands/funkyfish-logo-square.jpg", hero: "assets/brands/funkyfish-hero-5.jpg", stores: 5, imageFit: "cover" },
  { key: "bottega",  name: "Bottega Verde", tagline: "Italian beauty & wellness · Since 1972",      color: "#5F7C4A", ink: "#FFFFFF", category: "Beauty",   since: "2015", image: "assets/brands/bottega-product-1.jpg",     hero: "assets/brands/bottega-hero.jpg",     stores: 4, imageFit: "cover" },
  { key: "livewell", name: "Livewell",      tagline: "Better health, better you",                   color: "#6FA0C5", ink: "#FFFFFF", category: "Health",   since: "2017", image: "assets/brands/livewell-3-hires.jpg",      hero: "assets/brands/livewell-2-hires.jpg", stores: 1, imageFit: "cover" },
  { key: "yadea",    name: "Yadea",         tagline: "Electrify your life · Global No.1 e-mobility",color: "#0F172A", ink: "#FFFFFF", category: "Mobility", since: "2019", image: "assets/yadea/hero-mint.png",              hero: "assets/yadea/hero-mint.png",         stores: 3, imageFit: "cover" },
];

/* Single source of truth for the group-level store total.
   Always equals the sum of BRANDS[].stores, so changing a brand count
   automatically updates the home stat, the B2B trust band, and the contact eyebrow. */
const TAMAK_TOTAL_STORES = BRANDS.reduce((sum, b) => sum + (b.stores || 0), 0);
window.TAMAK_TOTAL_STORES = TAMAK_TOTAL_STORES;

/* Real per-brand socials, mined from each brand's own site mirror.
   Used by the brand page footer block; missing handles fall through silently. */
const BRAND_SOCIALS = {
  bottega: {
    instagram: "https://instagram.com/bottegaverdemauritius/",
    facebook:  "https://facebook.com/profile.php?id=61573594702841",
    tiktok:    "https://tiktok.com/@bottegaverdemaurice",
    email:     "communication@tamakgroup.com",
    phone:     "+230 233 0020",
  },
  yadea: {
    instagram: "https://instagram.com/yadea_mauritius",
    facebook:  "https://facebook.com/profile.php?id=61578977105527",
    tiktok:    "https://tiktok.com/@yadea.mauritius",
    email:     "info@yadea.mu",
    phone:     "+230 233 0020",
    whatsapp:  "+230 5 936 9309",
  },
};

/* B2B units (separate from retail brands) */
const B2B_UNITS = [
  { key: "posterita", name: "Posterita",       tagline: "POS systems for modern retail",        color: "#0F172A" },
  { key: "distrib",   name: "Tamak Distribution", tagline: "Logistics & supply chain",          color: "#475569" },
  { key: "eco",       name: "Eco Products",    tagline: "Sustainable B2B solutions",            color: "#16A34A" },
  { key: "fleet",     name: "Yadea Fleets",    tagline: "Electric mobility for business",       color: "#CC1B2B" },
];

window.Placeholder = Placeholder;
window.Eyebrow = Eyebrow;
window.Tag = Tag;
window.Btn = Btn;
window.CountUp = CountUp;
window.Reveal = Reveal;
window.Marquee = Marquee;
window.BRANDS = BRANDS;
window.B2B_UNITS = B2B_UNITS;
