/* ui.jsx — shared primitives: reveal hook, buttons, phone frame, animated WhatsApp thread, floating cards, image slot. */

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

/* Reveal-on-scroll: adds .in when element enters viewport. */
function useReveal() {
  useEffect(() => {
    const reduce = matchMedia("(prefers-reduced-motion: reduce)").matches;
    if (reduce) return; // content already visible by default

    const root = document.documentElement;
    let raf = 0;
    const check = () => {
      raf = 0;
      const vh = window.innerHeight || document.documentElement.clientHeight;
      document.querySelectorAll("[data-reveal]:not(.in)").forEach((e) => {
        const r = e.getBoundingClientRect();
        if (r.top < vh * 0.92 && r.bottom > -40) {
          const d = e.getAttribute("data-delay");
          if (d) e.style.transitionDelay = d + "ms";
          e.classList.add("in");
        }
      });
    };
    const onScroll = () => { if (!raf) raf = requestAnimationFrame(check); };

    let cleanup = () => {};
    // Probe: confirm the renderer actually ticks rAF before hiding anything.
    let ticks = 0;
    const probe = () => {
      ticks++;
      if (ticks < 2) { requestAnimationFrame(probe); return; }
      // real, animating browser → enable hide-then-reveal
      root.classList.add("js-reveal");
      check();
      requestAnimationFrame(check); // first paint with hidden state, then reveal above-fold
      window.addEventListener("scroll", onScroll, { passive: true });
      window.addEventListener("resize", onScroll, { passive: true });
      const mo = new MutationObserver(onScroll);
      mo.observe(document.body, { childList: true, subtree: true });
      cleanup = () => {
        window.removeEventListener("scroll", onScroll);
        window.removeEventListener("resize", onScroll);
        mo.disconnect();
        if (raf) cancelAnimationFrame(raf);
      };
    };
    const probeId = requestAnimationFrame(probe);
    return () => { cancelAnimationFrame(probeId); cleanup(); };
  }, []);
}

/* Smooth-scroll helper for in-page anchors. */
function scrollToId(id) {
  const el = document.getElementById(id);
  if (!el) return;
  const top = el.getBoundingClientRect().top + window.scrollY - 76;
  window.scrollTo({ top, behavior: matchMedia("(prefers-reduced-motion: reduce)").matches ? "auto" : "smooth" });
}

/* Buttons -------------------------------------------------------------- */

/* Google Play store link (placeholder — swap for the real listing). */
const APP_URL = "https://play.google.com/store/apps/details?id=ng.mypa.app";

/* Play-store badge button — dark pill, colour mark + "GET IT ON / Google Play". */
function PlayBtn({ className = "", tone = "dark", label = "Get it on", ...p }) {
  const tones = {
    dark: "bg-brand-950 text-white hover:bg-ink ring-1 ring-black/10",
    light: "bg-white text-brand-900 hover:bg-cream ring-1 ring-brand-700/12",
    onDark: "bg-white text-brand-900 hover:bg-cream",
  };
  return (
    <a
      href={APP_URL}
      target="_blank"
      rel="noopener"
      aria-label="Get My PA on Google Play"
      className={
        "focus-ring group inline-flex items-center gap-3 rounded-2xl px-5 py-3 transition-all duration-150 hover:-translate-y-0.5 " +
        tones[tone] + " " + className
      }
      {...p}
    >
      <Icons.GooglePlayColor size={26} className="flex-none" />
      <span className="text-left leading-none">
        <span className="block text-[10px] font-semibold uppercase tracking-[0.16em] opacity-70">{label}</span>
        <span className="mt-1 block font-display text-[17px] font-extrabold tracking-tight">Google Play</span>
      </span>
    </a>
  );
}

/* Inline amber primary that points at the store (keeps brand CTA look). */
function PlayPrimary({ children, className = "", ...p }) {
  return (
    <a
      href={APP_URL}
      target="_blank"
      rel="noopener"
      className={"btn-amber focus-ring inline-flex items-center justify-center gap-2.5 whitespace-nowrap rounded-full py-2.5 pl-2.5 pr-6 text-[15px] " + className}
      {...p}
    >
      <span className="flex h-7 w-7 flex-none items-center justify-center rounded-full bg-white shadow-sm">
        <Icons.GooglePlayColor size={16} />
      </span>
      {children || "Get it on Google Play"}
    </a>
  );
}

function PrimaryBtn({ children, className = "", as = "button", ...p }) {
  const Tag = as;
  return (
    <Tag
      className={"btn-amber focus-ring inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-full px-7 py-3.5 text-[15px] " + className}
      {...p}
    >
      {children}
    </Tag>
  );
}

function GhostBtn({ children, className = "", tone = "light", as = "button", ...p }) {
  const Tag = as;
  const tones = {
    light:
      "border border-brand-700/15 bg-white/70 text-brand-800 hover:bg-white hover:border-brand-700/25",
    onDark:
      "border border-white/25 bg-white/5 text-cream hover:bg-white/12 backdrop-blur-sm",
  };
  return (
    <Tag
      className={
        "focus-ring inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-full px-7 py-3.5 text-[15px] font-semibold transition-all duration-150 " +
        tones[tone] + " " + className
      }
      {...p}
    >
      {children}
    </Tag>
  );
}

/* Section wrapper with eyebrow + heading ------------------------------- */
function Eyebrow({ children, onDark }) {
  return (
    <span
      className={
        "inline-flex items-center gap-2 rounded-full px-3.5 py-1.5 text-[12.5px] font-semibold uppercase tracking-[0.14em] " +
        (onDark
          ? "bg-white/10 text-amber-400 ring-1 ring-white/15"
          : "bg-brand-50 text-brand-600 ring-1 ring-brand-100")
      }
    >
      <span className="h-1.5 w-1.5 rounded-full bg-amber-500" />
      {children}
    </span>
  );
}

/* Logo lockup ---------------------------------------------------------- */
function Logo({ size = 38, onDark }) {
  return (
    <span className="inline-flex items-center gap-2.5 select-none">
      <LogoMark size={size} onDark={onDark} />
      <span className={"font-display text-[22px] font-extrabold tracking-tight whitespace-nowrap " + (onDark ? "text-white" : "text-[#16201c]")}>
        My<span style={{ color: "#f59e0b" }}>PA</span>
      </span>
    </span>
  );
}

/* Phone frame ---------------------------------------------------------- */
function PhoneFrame({ children, className = "", glow = true }) {
  return (
    <div className={"relative " + className}>
      {glow && (
        <div className="pointer-events-none absolute -inset-8 -z-10 rounded-[3rem] bg-amber-500/20 blur-3xl" aria-hidden="true" />
      )}
      <div className="relative mx-auto w-[300px] rounded-[2.6rem] bg-brand-950 p-2.5 shadow-lift ring-1 ring-black/10 sm:w-[324px]">
        <div className="absolute left-1/2 top-2.5 z-20 h-[26px] w-[108px] -translate-x-1/2 rounded-full bg-brand-950" aria-hidden="true" />
        <div className="relative overflow-hidden rounded-[2.1rem] bg-white">
          {children}
        </div>
      </div>
    </div>
  );
}

/* A single WhatsApp-style chat bubble */
function Bubble({ side, children, time, tick, anim }) {
  const me = side === "me";
  return (
    <div className={"flex " + (me ? "justify-end" : "justify-start")}>
      <div
        className={
          "relative max-w-[78%] rounded-2xl px-3 py-2 text-[13px] leading-snug shadow-sm " +
          (me
            ? "rounded-br-md bg-[#DCF8C6] text-[#0A2912]"
            : "rounded-bl-md bg-white text-brand-950 ring-1 ring-black/5") +
          (anim ? " animate-pop" : "")
        }
        style={anim ? { animationDelay: anim } : undefined}
      >
        {children}
        <span className={"mt-0.5 flex items-center justify-end gap-1 text-[10px] " + (me ? "text-[#4a7a4a]" : "text-brand-950/40")}>
          {time}
          {me && (
            <svg width="15" height="11" viewBox="0 0 16 11" fill="none" aria-hidden="true">
              <path d="M1 5.5 4 8.5 9.5 2.5" stroke="#34B7F1" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" />
              <path d="M6 5.5 9 8.5 14.5 2.5" stroke="#34B7F1" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
          )}
        </span>
      </div>
    </div>
  );
}

/* Animated WhatsApp thread that types out the assistant's reply on loop. */
function WhatsAppThread({ compact }) {
  const script = [
    { side: "them", text: "Good evening 👋 Do you still have the green ankara gown in size 14? And do you deliver to Lekki?", time: "11:48 PM" },
    { side: "me", text: "Yes ma! The emerald ankara (size 14) is in stock — ₦18,500. We deliver to Lekki, ₦2,000, arrives tomorrow before 4pm. Want me to reserve it? 🌿", time: "11:48 PM", ai: true },
    { side: "them", text: "Perfect. Please reserve it 🙏", time: "11:49 PM" },
    { side: "me", text: "Done ✅ I've sent your receipt and payment link. Thank you for shopping with us!", time: "11:49 PM", ai: true },
  ];
  const [count, setCount] = useState(matchMedia("(prefers-reduced-motion: reduce)").matches ? script.length : 1);
  const [typing, setTyping] = useState(false);

  useEffect(() => {
    if (matchMedia("(prefers-reduced-motion: reduce)").matches) return;
    let t;
    if (count < script.length) {
      const next = script[count];
      setTyping(next.side === "me");
      t = setTimeout(() => { setTyping(false); setCount((c) => c + 1); }, next.side === "me" ? 1700 : 1100);
    } else {
      t = setTimeout(() => setCount(1), 4200); // loop
    }
    return () => clearTimeout(t);
  }, [count]);

  return (
    <div className="flex h-full flex-col bg-[#E5DDD4]">
      {/* chat header */}
      <div className="flex items-center gap-2.5 bg-brand-700 px-3.5 pb-2.5 pt-9 text-white">
        <div className="flex h-9 w-9 items-center justify-center rounded-full bg-amber-500 text-[15px] font-bold text-brand-900">BL</div>
        <div className="min-w-0 flex-1 leading-tight">
          <div className="truncate text-[13.5px] font-semibold">Bisi's Boutique</div>
          <div className="flex items-center gap-1 text-[10.5px] text-white/75">
            <span className="inline-flex items-center gap-1 rounded-full bg-amber-500/90 px-1.5 py-px font-semibold text-brand-900">
              My PA active
            </span>
          </div>
        </div>
        <Icons.MessageCircle size={17} className="text-white/80" />
      </div>

      {/* messages */}
      <div className="flex flex-1 flex-col gap-2 overflow-hidden px-3 py-3">
        <div className="mx-auto rounded-full bg-white/70 px-2.5 py-0.5 text-[10px] font-medium text-brand-950/50">
          Today · 11:48 PM
        </div>
        {script.slice(0, count).map((m, i) => (
          <Bubble key={i} side={m.side} time={m.time} anim={i === count - 1 ? "0ms" : null}>
            {m.ai && (
              <span className="mb-0.5 flex items-center gap-1 text-[10px] font-bold uppercase tracking-wide text-brand-600">
                <Icons.Sparkles size={11} /> My PA
              </span>
            )}
            {m.text}
          </Bubble>
        ))}
        {typing && (
          <div className="flex justify-end">
            <div className="flex items-center gap-1 rounded-2xl rounded-br-md bg-[#DCF8C6] px-3 py-2.5">
              {[0, 1, 2].map((d) => (
                <span key={d} className="h-1.5 w-1.5 rounded-full bg-brand-600/60" style={{ animation: "blink 1s infinite", animationDelay: d * 0.15 + "s" }} />
              ))}
            </div>
          </div>
        )}
      </div>

      {/* input bar */}
      <div className="flex items-center gap-2 bg-[#E5DDD4] px-3 pb-3 pt-1">
        <div className="flex flex-1 items-center rounded-full bg-white px-3.5 py-2 text-[12px] text-brand-950/40 shadow-sm">
          My PA is handling this chat…
        </div>
        <div className="flex h-9 w-9 items-center justify-center rounded-full bg-brand-600 text-white shadow-sm">
          <Icons.Send size={16} />
        </div>
      </div>
    </div>
  );
}

/* Floating stat card used over hero visuals */
function FloatCard({ className = "", style, children }) {
  return (
    <div
      className={"absolute z-20 rounded-2xl bg-white/95 px-3.5 py-3 shadow-soft ring-1 ring-black/5 backdrop-blur " + className}
      style={style}
    >
      {children}
    </div>
  );
}

/* image-slot wrapper that respects dark mode styling of the placeholder */
function Slot({ id, placeholder, shape = "rounded", radius, className = "", style }) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (el && placeholder) el.setAttribute("placeholder", placeholder);
  }, [placeholder]);
  return (
    <image-slot
      ref={ref}
      id={id}
      shape={shape}
      radius={radius}
      class={className}
      style={style}
    ></image-slot>
  );
}

Object.assign(window, {
  useReveal, scrollToId, PrimaryBtn, GhostBtn, PlayBtn, PlayPrimary, APP_URL, Eyebrow, Logo,
  PhoneFrame, Bubble, WhatsAppThread, FloatCard, Slot,
});
