// Общие UI-примитивы BATONS'ON (editorial / minimal)
const { useState, useEffect, useRef, useMemo } = React;

// Плейсхолдер фото
function Ph({ label, ratio }) {
  return (
    <div className="ph" style={ratio ? { aspectRatio: ratio } : null}>
      <div className="ph-stripes" />
      <span className="ph-label">{label}</span>
    </div>
  );
}
function Media({ p, ratio }) {
  if (p.img) return <img className="media-img" src={RES(p.img)} alt={p.name} loading="lazy" style={{ transform: `scale(${Number(p.scale) || 1})` }} />;
  return <Ph label={p.ph || "фото"} ratio={ratio} />;
}

function Stars({ value = 5, sold }) {
  return (
    <span className="stars">
      <span className="stars-fill">{"★".repeat(Math.round(value))}</span>
      <span className="stars-val">{value.toFixed(1)}</span>
      {sold != null && <span>· {sold.toLocaleString("ru-RU")}</span>}
    </span>
  );
}
function Badge({ children }) { return children ? <span className="badge">{children}</span> : null; }
function Swatches({ colors = [], active, onPick, max }) {
  const shown = max ? colors.slice(0, max) : colors;
  const extra = max ? colors.length - shown.length : 0;
  return (
    <div className="swatches">
      {shown.map((c, i) => (
        <button key={i} className={"swatch" + (active === i ? " on" : "")} style={{ background: c }}
          onClick={(e) => { e.stopPropagation(); onPick && onPick(i); }} aria-label={"Цвет " + (i + 1)} aria-pressed={active === i} />
      ))}
      {extra > 0 && <span className="swatch-more">+{extra}</span>}
    </div>
  );
}

// цикл индексов 0..n-1 со сменой
function useCycle(n, ms, offset = 0) {
  const [i, setI] = useState(offset % n);
  useEffect(() => {
    const t = setInterval(() => setI((x) => (x + 1) % n), ms);
    return () => clearInterval(t);
  }, [n, ms]);
  return i;
}

// Видео, которое перелистывает ролики (разные и меняются)
function RotatingVideo({ reels, ms = 6000, offset = 0, poster }) {
  const idx = useCycle(reels.length, ms, offset);
  return (
    <div className="hero-bg">
      {reels.map((src, i) => (
        <video key={i} className={i === idx ? "show" : ""} src={src} muted loop playsInline autoPlay preload="auto" poster={poster} />
      ))}
    </div>
  );
}

// Карточка товара — premium
function ProductCard({ p, onOpen, onAdd }) {
  const [ci, setCi] = useState(0);
  const [wish, setWish] = useState(false);
  const [added, setAdded] = useState(false);
  const [mi, setMi] = useState(0);
  const addedT = useRef(null);
  const mediaRef = useRef(null);
  const videoRef = useRef(null);
  const gallery = p.mediaItems
    ? getProductMedia(p)
    : p.videoFirst && p.video
      ? [{ type: "video", src: p.video }, ...(p.images || [p.img]).filter(Boolean).map((img) => ({ type: "image", img }))]
      : null;
  const active = gallery ? gallery[Math.min(mi, gallery.length - 1)] : null;
  const playCurrentVideo = () => {
    const video = videoRef.current;
    if (!video) return;
    video.muted = true;
    video.volume = 0;
    video.play().catch(() => {});
  };
  const pauseCurrentVideo = () => videoRef.current && videoRef.current.pause();

  useEffect(() => { setMi(0); }, [p.id]);
  useEffect(() => {
    if (!gallery || !active || active.type !== "video" || !mediaRef.current) return;
    const media = mediaRef.current;
    const isTouch = window.matchMedia("(hover: none), (pointer: coarse)").matches;
    if (!isTouch) {
      if (media.matches(":hover")) playCurrentVideo();
      return;
    }
    if (!("IntersectionObserver" in window)) {
      playCurrentVideo();
      return;
    }
    const observer = new IntersectionObserver(([entry]) => {
      if (entry.isIntersecting) playCurrentVideo();
      else pauseCurrentVideo();
    }, { threshold: 0.45 });
    observer.observe(media);
    return () => observer.disconnect();
  }, [p.id, mi]);

  const open = () => onOpen(p);
  const quickAdd = (e) => {
    e.stopPropagation();
    onAdd(p, { color: ci });
    setAdded(true);
    clearTimeout(addedT.current);
    addedT.current = setTimeout(() => setAdded(false), 1500);
  };
  const moveMedia = (e, next) => {
    e.preventDefault();
    e.stopPropagation();
    setMi(next);
  };
  const discount = p.old ? Math.round((1 - p.price / p.old) * 100) : 0;
  return (
    <article className={`card card-${p.id}`} tabIndex={0} role="link" aria-label={p.name + ", " + RUB(p.price)}
      onClick={open}
      onKeyDown={(e) => { if (e.key === "Enter" && e.target === e.currentTarget) { e.preventDefault(); open(); } }}>
      <div className="card-media" ref={mediaRef}
        onMouseEnter={() => { if (window.matchMedia("(hover: hover)").matches) playCurrentVideo(); }}
        onMouseLeave={() => { if (window.matchMedia("(hover: hover)").matches) pauseCurrentVideo(); }}>
        {active
          ? active.type === "video"
            ? <video ref={videoRef} className="card-video" src={RES(active.src)} muted loop playsInline preload="auto" poster={RES(p.poster || p.img)}
                style={{ transform: `scale(${Number(active.scale) || 1})` }}
                onLoadedMetadata={(e) => { const start = Number(active.trimStart) || 0; if (start) e.currentTarget.currentTime = start; }}
                onTimeUpdate={(e) => { const start = Number(active.trimStart) || 0; const end = Number(active.trimEnd) || 0; const last = e.currentTarget.duration - end; if (Number.isFinite(last) && e.currentTarget.currentTime >= last) e.currentTarget.currentTime = start; }} />
            : <Media p={{ ...active, name: p.name }} />
          : <Media p={p} />}
        {gallery && mi > 0 && <button className="media-arrow prev" onClick={(e) => moveMedia(e, mi - 1)} aria-label="Предыдущее медиа"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m15 18-6-6 6-6" /></svg></button>}
        {gallery && mi < gallery.length - 1 && <button className="media-arrow next" onClick={(e) => moveMedia(e, mi + 1)} aria-label="Следующее медиа"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m9 18 6-6-6-6" /></svg></button>}
        {p.badge && <div className="card-badge"><Badge>{p.badge}</Badge></div>}
        {discount > 0 && <div className="card-off">−{discount}%</div>}
        <button className={"card-wish" + (wish ? " on" : "")} onClick={(e) => { e.stopPropagation(); setWish((w) => !w); }}
          aria-pressed={wish} aria-label={wish ? "Убрать из избранного" : "В избранное"}>
          {wish ? "♥" : "♡"}
        </button>
        <button className={"card-quick" + (added ? " added" : "")} onClick={quickAdd}>
          {added ? "Добавлено ✓" : "Добавить в корзину"}
        </button>
      </div>
      <div className="card-body">
        <div className="card-top">
          <h3 className="card-name">{p.name}</h3>
          {p.brand && <span className="card-brand">BATONS'ON</span>}
        </div>
        <Stars value={p.rating} sold={p.sold} />
        <div className="card-foot">
          <div className="price">
            <span className="price-now">{RUB(p.price)}</span>
            {p.old && <span className="price-old">{RUB(p.old)}</span>}
          </div>
          <Swatches colors={p.colors} active={ci} onPick={setCi} max={4} />
        </div>
      </div>
    </article>
  );
}
Object.assign(window, { Ph, Media, Stars, Badge, Swatches, ProductCard, useCycle, RotatingVideo });
