// ARS — shared UI primitives
const { useState, useEffect, useRef, useCallback } = React;

const LOGO = (window.__resources && window.__resources.logo) || "assets/logo.png";

/* ---------- simple stroke icons ---------- */
const ICONS = {
  ball: "M12 3a9 9 0 0 1 9 9 9 9 0 0 1-9 9 9 9 0 0 1-9-9 9 9 0 0 1 9-9ZM4 7c4 1 6 4 6 9M20 7c-4 1-6 4-6 9",
  pin: "M12 21s7-6.3 7-11a7 7 0 1 0-14 0c0 4.7 7 11 7 11Z M12 10.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z",
  clock: "M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18ZM12 7.5V12l3 2",
  truck: "M3 6h11v9H3zM14 9h4l3 3v3h-7zM7 18.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM17.5 18.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z",
  bolt: "M13 2 4 14h6l-1 8 9-12h-6l1-8Z",
  check: "M5 12.5 10 17.5 19 7",
  phone: "M5 4h4l2 5-2.5 1.5a11 11 0 0 0 5 5L15 13l5 2v4a2 2 0 0 1-2 2A16 16 0 0 1 3 6a2 2 0 0 1 2-2Z",
  mail: "M3 6h18v12H3zM3 7l9 6 9-6",
  arrow: "M5 12h14M13 6l6 6-6 6",
  chevron: "M9 6l6 6-6 6",
  plus: "M12 5v14M5 12h14",
  minus: "M5 12h14",
  edit: "M4 20h4L19 9l-4-4L4 16v4ZM14 6l4 4",
  trash: "M4 7h16M9 7V4h6v3M6 7l1 13h10l1-13",
  lock: "M6 11h12v9H6zM8 11V8a4 4 0 1 1 8 0v3",
  star: "M12 3l2.6 5.6 6 .7-4.4 4 1.2 6L12 16.8 6.6 19.3l1.2-6-4.4-4 6-.7L12 3Z",
  x: "M6 6l12 12M18 6 6 18",
  user: "M12 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8ZM4 21a8 8 0 0 1 16 0",
  racquet: "M14.5 3a5.5 5.5 0 0 1 0 11 5.5 5.5 0 0 1 0-11ZM10.6 14.4 4 21M9 10.5l4 4M11.5 8l4.5 4.5",
  calendar: "M4 6h16v15H4zM4 10h16M8 3v4M16 3v4",
};
function Icon({ name, size = 22, stroke = 2, fill = "none", ...rest }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill={fill === "ball" ? "none" : fill}
      stroke="currentColor" strokeWidth={stroke} strokeLinecap="round" strokeLinejoin="round" {...rest}>
      <path d={ICONS[name]} />
    </svg>
  );
}

/* ---------- decorative tennis ball ---------- */
function BallMark({ size = 44, style }) {
  return (
    <span style={{ display: "inline-flex", width: size, height: size, borderRadius: "50%",
      background: "var(--ball)", color: "var(--navy-deep)", alignItems: "center", justifyContent: "center",
      boxShadow: "inset 0 0 0 2px rgba(14,38,73,.12)", ...style }}>
      <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="rgba(14,38,73,.45)" strokeWidth="1.6">
        <path d="M5 4c4 2 5 6 5 8s-1 6-5 8M19 4c-4 2-5 6-5 8s1 6 5 8" />
      </svg>
    </span>
  );
}

/* ---------- section heading ---------- */
function Heading({ eyebrow, title, sub, align = "left", light = false, maxSub }) {
  return (
    <div style={{ textAlign: align, maxWidth: align === "center" ? 760 : "none", margin: align === "center" ? "0 auto" : 0 }}>
      {eyebrow && (
        <div className="eyebrow" style={{ color: light ? "var(--ball)" : "var(--green)", marginBottom: 14,
          display: "flex", gap: 9, alignItems: "center", justifyContent: align === "center" ? "center" : "flex-start" }}>
          <span style={{ width: 26, height: 3, background: "currentColor", borderRadius: 3 }} />{eyebrow}
        </div>
      )}
      <h2 className="display" style={{ fontSize: "clamp(34px,5vw,58px)", color: light ? "#fff" : "var(--ink)" }}>{title}</h2>
      {sub && <p style={{ fontSize: 18, color: light ? "rgba(255,255,255,.78)" : "var(--ink-2)", marginTop: 16,
        maxWidth: maxSub || 620, marginInline: align === "center" ? "auto" : 0 }}>{sub}</p>}
    </div>
  );
}

/* ---------- reveal on scroll ---------- */
function Reveal({ children, delay = 0, as: Tag = "div", ...rest }) {
  const ref = useRef(null);
  const [seen, setSeen] = useState(() => !!window.__PRINT__);
  useEffect(() => {
    if (window.__PRINT__) { setSeen(true); return; }
    const el = ref.current; if (!el) return;
    const io = new IntersectionObserver((es) => {
      es.forEach((e) => { if (e.isIntersecting) { setSeen(true); io.disconnect(); } });
    }, { threshold: 0.12 });
    io.observe(el); return () => io.disconnect();
  }, []);
  return (
    <Tag ref={ref} style={{ opacity: seen ? 1 : 0, transform: seen ? "none" : "translateY(22px)",
      transition: `opacity .6s ease ${delay}ms, transform .6s cubic-bezier(.2,.7,.2,1) ${delay}ms` }} {...rest}>
      {children}
    </Tag>
  );
}

/* ---------- toast ---------- */
function useToast() {
  const [msg, setMsg] = useState(null);
  const show = useCallback((m) => {
    setMsg(m);
    clearTimeout(window.__arsToast);
    window.__arsToast = setTimeout(() => setMsg(null), 2400);
  }, []);
  const node = msg ? <div className="toast"><Icon name="check" size={17} stroke={3} style={{ color: "var(--ball)" }} />{msg}</div> : null;
  return [node, show];
}

/* ---------- money helpers ---------- */
const money = (n) => (n === 0 ? "FREE" : `$${n}`);

/* ---------- inline editable price (admin) ---------- */
function PriceTag({ value, editing, onChange, prefix = "$", suffix = "", free = true, align = "right" }) {
  if (!editing) {
    return <span style={{ fontWeight: 800, color: "var(--navy)", whiteSpace: "nowrap" }}>
      {free && value === 0 ? "FREE" : `${prefix}${value}${suffix}`}</span>;
  }
  return (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 4, background: "var(--ball)",
      padding: "3px 8px", borderRadius: 9, boxShadow: "inset 0 0 0 2px var(--ball-deep)" }}>
      <span style={{ fontWeight: 800, color: "var(--navy-deep)" }}>{prefix}</span>
      <input type="number" min="0" value={value}
        onChange={(e) => onChange(e.target.value === "" ? 0 : Math.max(0, parseInt(e.target.value, 10) || 0))}
        style={{ width: 52, border: "none", background: "transparent", fontWeight: 800, fontSize: 16,
          color: "var(--navy-deep)", textAlign: align, outline: "none",
          MozAppearance: "textfield" }} />
      {suffix && <span style={{ fontWeight: 700, color: "var(--navy-deep)", fontSize: 13 }}>{suffix}</span>}
    </span>
  );
}

/* ---------- text input editable (admin) ---------- */
function EditText({ value, editing, onChange, placeholder, style, bold }) {
  if (!editing) return <span style={style}>{value || <span style={{ color: "#aab" }}>{placeholder}</span>}</span>;
  return (
    <input value={value} placeholder={placeholder} onChange={(e) => onChange(e.target.value)}
      style={{ border: "1.5px dashed var(--green)", background: "var(--green-soft)", borderRadius: 7,
        padding: "3px 8px", fontWeight: bold ? 800 : 600, color: "var(--ink)", outline: "none",
        font: "inherit", ...style }} />
  );
}

/* ---------- realistic tennis ball (CSS seams) ---------- */
function TennisBall({ size = 420, style, glow = true }) {
  const seam = Math.max(2, Math.round(size * 0.03));
  const off = Math.round(size * 0.66);
  const ring = { position: "absolute", width: size, height: size, borderRadius: "50%",
    border: `${seam}px solid #FCFEF0`, top: 0, boxSizing: "border-box" };
  return (
    <div style={{ position: "relative", width: size, height: size, borderRadius: "50%", overflow: "hidden",
      background: "radial-gradient(circle at 34% 28%, #ECF65A 0%, var(--ball) 46%, var(--ball-deep) 100%)",
      boxShadow: glow ? "inset -16px -22px 46px rgba(0,0,0,.16), inset 14px 16px 36px rgba(255,255,255,.45)" : "none",
      ...style }}>
      {/* fuzzy speckle texture */}
      <div style={{ position: "absolute", inset: 0, borderRadius: "50%", opacity: .5, mixBlendMode: "soft-light",
        backgroundImage: "radial-gradient(rgba(0,0,0,.5) .5px, transparent .6px)", backgroundSize: `${Math.max(3, size*0.012)}px ${Math.max(3, size*0.012)}px` }} />
      <div style={{ ...ring, left: -off }} />
      <div style={{ ...ring, left: off }} />
    </div>
  );
}

Object.assign(window, { Icon, ICONS, BallMark, TennisBall, Heading, Reveal, useToast, money, PriceTag, EditText, LOGO });
