// Shared primitives used by all three variations.
// Each prototype variation is rendered inside a scroll-scoped <ProtoFrame/>
// that isolates the custom cursor, listens for its own scroll for parallax,
// and carries palette vars so all three styles can live on one page.

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

// ── Photo placeholders ──────────────────────────────────────────────────────
// Three styles requested: monochrome gradient, striped, abstract duotone.
// All render a label (slot description) + monospace id tag.
function Photo({ item, style = "grad", className = "", inset = null, aspect, frameClass = "" }) {
  const ar = aspect || item.aspect || "3/4";
  if (item.src) {
    return (
      <div className={"vw-ph " + className} style={{ aspectRatio: ar.replace("/", " / "), overflow:"hidden", ...inset }}>
        <img src={item.src} alt={item.title?.pl || ""} style={{ width:"100%", height:"100%", objectFit:"cover", objectPosition:"center top", display:"block" }} loading="lazy" />
      </div>
    );
  }
  const label =
    item.title?.pl?.toUpperCase() +
    (item.client ? ` · ${item.client.toUpperCase()}` : "");
  const id = item.id?.toUpperCase() || "—";
  const cls =
    "vw-ph " +
    (style === "striped" ? "vw-ph-striped" :
     style === "duotone" ? "vw-ph-duotone" : "vw-ph-grad") +
    " " + className;
  const duoA =
    item.tone === "a" ? "#2a2220" :
    item.tone === "b" ? "#1a2230" :
    item.tone === "c" ? "#231a14" : "#1e1e1e";
  const duoB = "#07090e";
  return (
    <div className={cls} style={{ aspectRatio: ar.replace("/", " / "), ...inset, "--duo-a": duoA, "--duo-b": duoB }}>
      <span className="vw-ph-id">{id}</span>
      <span className="vw-ph-label">{label || "PHOTO SLOT"}</span>
    </div>
  );
}

// ── Custom cursor ───────────────────────────────────────────────────────────
// Circle / crosshair / none. Runs per-ProtoFrame so hovering another variation
// swaps to its cursor. Hidden on touch. Uses pointerEvents:none so it never
// blocks clicks.
function useCursor({ containerRef, style = "circle", accentVar = "#C9A96E" }) {
  const cursorRef = useRef(null);
  const [isTouch] = useState(() =>
    typeof window !== "undefined" && matchMedia("(pointer: coarse)").matches
  );
  useEffect(() => {
    if (isTouch || style === "none") return;
    const el = containerRef.current;
    if (!el) return;
    let raf = 0;
    let x = -100, y = -100;
    let tx = x, ty = y;
    const onMove = (e) => {
      const r = el.getBoundingClientRect();
      tx = e.clientX - r.left;
      ty = e.clientY - r.top;
    };
    const onEnter = () => { if (cursorRef.current) cursorRef.current.style.opacity = 1; };
    const onLeave = () => { if (cursorRef.current) cursorRef.current.style.opacity = 0; };

    const onHoverable = (e) => {
      const hit = e.target && e.target.closest && e.target.closest("[data-cursor]");
      if (cursorRef.current) {
        const tag = hit?.getAttribute("data-cursor") || "";
        cursorRef.current.setAttribute("data-mode", tag);
      }
    };

    const tick = () => {
      x += (tx - x) * 0.18;
      y += (ty - y) * 0.18;
      if (cursorRef.current) cursorRef.current.style.transform = `translate3d(${x}px, ${y}px, 0) translate(-50%, -50%)`;
      raf = requestAnimationFrame(tick);
    };
    el.addEventListener("mousemove", onMove);
    el.addEventListener("mouseenter", onEnter);
    el.addEventListener("mouseleave", onLeave);
    el.addEventListener("mouseover", onHoverable);
    raf = requestAnimationFrame(tick);
    return () => {
      el.removeEventListener("mousemove", onMove);
      el.removeEventListener("mouseenter", onEnter);
      el.removeEventListener("mouseleave", onLeave);
      el.removeEventListener("mouseover", onHoverable);
      cancelAnimationFrame(raf);
    };
  }, [containerRef, style, isTouch]);

  if (isTouch || style === "none") return { cursorRef, isTouch, node: null };

  return {
    cursorRef, isTouch,
    node: (
      <div
        ref={cursorRef}
        className="vw-cursor"
        data-style={style}
        style={{
          position: "absolute", left: 0, top: 0, pointerEvents: "none",
          zIndex: 9999, opacity: 0,
          mixBlendMode: style === "star" ? "normal" : "difference",
        }}
      >
        {style === "circle" ? (
          <CircleCursor accent={accentVar} />
        ) : style === "star" ? (
          <StarCursor accent={accentVar} />
        ) : (
          <CrosshairCursor accent={accentVar} />
        )}
      </div>
    )
  };
}

function CircleCursor({ accent }) {
  return (
    <div style={{ position: "relative", width: 80, height: 80 }}>
      <div style={{
        position:"absolute", inset:0, border:"1px solid rgba(255,255,255,0.85)",
        borderRadius:"50%",
      }} />
      <div style={{
        position:"absolute", left:"50%", top:"50%", width:6, height:6,
        background:"rgba(255,255,255,0.95)", borderRadius:"50%",
        transform:"translate(-50%,-50%)"
      }} />
      <svg viewBox="0 0 100 100" style={{
        position:"absolute", inset:0, animation:"vw-spin 12s linear infinite",
      }}>
        <defs>
          <path id="vw-circle-path" d="M 50,50 m -38,0 a 38,38 0 1,1 76,0 a 38,38 0 1,1 -76,0" />
        </defs>
        <text fontFamily="'Inter', sans-serif" fontSize="8" fontWeight="500" letterSpacing="0.3em" fill="#fff">
          <textPath href="#vw-circle-path">· EXPLORE · ZOBACZ · EXPLORE · ZOBACZ ·</textPath>
        </text>
      </svg>
    </div>
  );
}

function StarCursor({ accent }) {
  return (
    <div style={{ position: "relative", width: 52, height: 52 }}>
      <svg viewBox="0 0 52 52" style={{ position: "absolute", inset: 0, animation: "vw-star-spin 4s linear infinite", filter: "drop-shadow(0 0 6px rgba(201,169,110,0.7))" }}>
        <path d="M26 3 L29 21 L47 24 L29 27 L26 45 L23 27 L5 24 L23 21 Z" fill="rgba(201,169,110,0.95)" />
      </svg>
      <div style={{
        position: "absolute", left: "50%", top: "50%",
        width: 7, height: 7, borderRadius: "50%",
        background: "#fff",
        transform: "translate(-50%, -50%)",
        animation: "vw-star-pulse 1.4s ease-in-out infinite",
        boxShadow: "0 0 8px 2px rgba(201,169,110,0.8)",
      }} />
    </div>
  );
}

function CrosshairCursor({ accent }) {
  return (
    <div style={{ position:"relative", width: 48, height: 48 }}>
      <div style={{position:"absolute", left:"50%", top:0, width:1, height:"100%", background:"rgba(255,255,255,0.9)", transform:"translateX(-50%)"}}/>
      <div style={{position:"absolute", top:"50%", left:0, height:1, width:"100%", background:"rgba(255,255,255,0.9)", transform:"translateY(-50%)"}}/>
      <div style={{position:"absolute", left:"50%", top:"50%", width:12, height:12, border:"1px solid rgba(255,255,255,0.9)", transform:"translate(-50%,-50%)"}}/>
    </div>
  );
}

// ── Counter-up animation ────────────────────────────────────────────────────
function CounterUp({ to, suffix = "", duration = 1400, className = "", style = {} }) {
  const [value, setValue] = useState(0);
  const ref = useRef(null);
  const started = useRef(false);
  useEffect(() => {
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting && !started.current) {
          started.current = true;
          const t0 = performance.now();
          const step = (t) => {
            const p = Math.min(1, (t - t0) / duration);
            const eased = 1 - Math.pow(1 - p, 3);
            setValue(Math.round(to * eased));
            if (p < 1) requestAnimationFrame(step);
          };
          requestAnimationFrame(step);
        }
      });
    }, { threshold: 0.4 });
    if (ref.current) io.observe(ref.current);
    return () => io.disconnect();
  }, [to, duration]);
  return <span ref={ref} className={className} style={style}>{value}{suffix}</span>;
}

// ── In-view fade (generic scroll-triggered animation) ───────────────────────
function InView({ children, as = "div", delay = 0, className = "", style = {}, rootRef, y = 20, once = true }) {
  const Tag = as;
  const ref = useRef(null);
  const [shown, setShown] = useState(false);
  useEffect(() => {
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting) { setShown(true); if (once) io.disconnect(); }
        else if (!once) setShown(false);
      });
    }, { threshold: 0.15, root: rootRef?.current || null });
    if (ref.current) io.observe(ref.current);
    return () => io.disconnect();
  }, [rootRef, once]);
  return (
    <Tag
      ref={ref}
      className={className}
      style={{
        transform: shown ? "none" : `translateY(${y}px)`,
        opacity: shown ? 1 : 0,
        transition: `transform 900ms cubic-bezier(.2,.7,.3,1) ${delay}ms, opacity 900ms ease ${delay}ms`,
        ...style,
      }}
    >{children}</Tag>
  );
}

// ── Stagger text reveal for headlines ───────────────────────────────────────
function StaggerText({ text, className = "", style = {}, delay = 0, stagger = 60, rootRef }) {
  const ref = useRef(null);
  const [shown, setShown] = useState(false);
  useEffect(() => {
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => { if (e.isIntersecting) { setShown(true); io.disconnect(); } });
    }, { threshold: 0.2, root: rootRef?.current || null });
    if (ref.current) io.observe(ref.current);
    return () => io.disconnect();
  }, [rootRef]);
  return (
    <span ref={ref} className={className} style={style}>
      {text.split(" ").map((word, wi) => (
        <span key={wi} style={{ display:"inline-block", whiteSpace:"nowrap", marginRight:"0.28em" }}>
          {[...word].map((c, ci) => (
            <span
              key={ci}
              style={{
                display: "inline-block",
                transform: shown ? "none" : "translateY(0.8em)",
                opacity: shown ? 1 : 0,
                filter: shown ? "blur(0)" : "blur(6px)",
                transition: `all 700ms cubic-bezier(.2,.7,.3,1) ${delay + (wi * 80) + ci * stagger}ms`,
              }}
            >{c}</span>
          ))}
        </span>
      ))}
    </span>
  );
}

// ── Lightbox ────────────────────────────────────────────────────────────────
function Lightbox({ items, index, onClose, onPrev, onNext, photoStyle = "grad", lang = "pl" }) {
  useEffect(() => {
    if (index == null) return;
    const onKey = (e) => {
      if (e.key === "Escape") onClose();
      if (e.key === "ArrowLeft") onPrev();
      if (e.key === "ArrowRight") onNext();
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [index, onClose, onPrev, onNext]);

  if (index == null) return null;
  const item = items[index];
  return (
    <div
      role="dialog"
      style={{
        position: "fixed", inset: 0, zIndex: 2000,
        background: "rgba(6,6,8,0.82)",
        backdropFilter: "blur(18px) saturate(140%)",
        display: "flex", alignItems: "center", justifyContent: "center",
        padding: "4vw", animation: "vw-fade 220ms ease",
      }}
      onClick={onClose}
    >
      <button
        data-cursor="prev"
        onClick={(e) => { e.stopPropagation(); onPrev(); }}
        style={lbBtnStyle("left")}>←</button>
      <button
        data-cursor="next"
        onClick={(e) => { e.stopPropagation(); onNext(); }}
        style={lbBtnStyle("right")}>→</button>
      <button
        onClick={onClose}
        style={{
          position: "absolute", top: 24, right: 24, width: 44, height: 44,
          borderRadius: "50%", border: "1px solid rgba(255,255,255,0.3)",
          background: "transparent", color: "#fff", cursor: "pointer",
          fontSize: 20, lineHeight: 1,
        }}>✕</button>

      <div
        onClick={(e) => e.stopPropagation()}
        style={{
          maxWidth: "min(1200px, 80vw)",
          maxHeight: "82vh",
          width: "auto",
          display: "flex", flexDirection: "column", gap: 16,
        }}>
        <div style={{ maxHeight: "72vh", display:"flex", justifyContent:"center" }}>
          <div style={{ maxHeight: "72vh", display:"flex" }}>
            <Photo
              key={item.id}
              item={item}
              style={photoStyle}
              inset={{ height:"72vh", width:"auto" }}
            />
          </div>
        </div>
        <div style={{ display:"flex", justifyContent:"space-between", alignItems:"baseline",
          color:"#fff", fontFamily:"Inter, sans-serif", fontSize: 12, letterSpacing:"0.1em", textTransform:"uppercase" }}>
          <div>{item.title[lang]} · {item.client}</div>
          <div style={{opacity:0.55}}>{index + 1} / {items.length}</div>
        </div>
      </div>
    </div>
  );
}
function lbBtnStyle(side) {
  return {
    position: "absolute",
    [side]: 24,
    top: "50%", transform: "translateY(-50%)",
    width: 56, height: 56, borderRadius: "50%",
    border: "1px solid rgba(255,255,255,0.25)",
    background: "transparent", color: "#fff",
    fontSize: 22, cursor: "pointer", zIndex: 10,
  };
}

// ── Marquee ────────────────────────────────────────────────────────────────
function Marquee({ items, speed = 40, className = "", separator = "·", pauseOnHover = true, fontSize = "clamp(52px, 7vw, 110px)", fontFamily = "var(--vw-display, 'Cormorant Garamond', serif)", letterSpacing = "-0.01em" }) {
  const ref = useRef(null);
  const [paused, setPaused] = useState(false);
  return (
    <div
      ref={ref}
      onMouseEnter={() => pauseOnHover && setPaused(true)}
      onMouseLeave={() => pauseOnHover && setPaused(false)}
      className={className}
      style={{ overflow:"hidden", display:"flex", width:"100%" }}>
      <div style={{
        display:"flex", gap: 80, whiteSpace:"nowrap",
        animation: `vw-marq ${speed}s linear infinite`,
        animationPlayState: paused ? "paused" : "running",
        fontFamily, fontSize, letterSpacing, fontWeight: 300,
      }}>
        {[...items, ...items, ...items].map((t, i) => (
          <span key={i} style={{display:"inline-flex", alignItems:"center", gap:80}}>
            <span>{t}</span>
            <span style={{opacity:0.35}}>{separator}</span>
          </span>
        ))}
      </div>
    </div>
  );
}

// ── Contact form with submit animation ──────────────────────────────────────
function ContactForm({ lang = "pl", accent = "#C9A96E", tone = "dark" }) {
  const [state, setState] = useState("idle"); // idle / submitting / done
  const submit = (e) => {
    e.preventDefault();
    if (state !== "idle") return;
    setState("submitting");
    setTimeout(() => setState("done"), 1400);
  };
  const L = lang === "pl" ? {
    name: "Imię i nazwisko", company: "Firma", email: "Email", type: "Rodzaj sesji",
    msg: "O czym myślisz?", types: ["Headshoty / C-suite","Kampania","Event","Retainer","Inna"],
    submit: "Wyślij", sending: "Wysyłam…", done: "Odezwę się w 24h",
    intro: "Pracujmy razem", sub: "Odpowiadam w ciągu 24 godzin. Bez automatów, bez CRM-a."
  } : {
    name: "Full name", company: "Company", email: "Email", type: "Session type",
    msg: "What do you have in mind?", types: ["Headshots / C-suite","Campaign","Event","Retainer","Other"],
    submit: "Send", sending: "Sending…", done: "I'll respond within 24h",
    intro: "Let's work together", sub: "I respond within 24 hours. No automations, no CRM."
  };
  const bg = tone === "dark" ? "transparent" : "transparent";
  const fg = tone === "dark" ? "rgba(255,255,255,0.92)" : "#1a1814";
  const border = tone === "dark" ? "rgba(255,255,255,0.2)" : "rgba(0,0,0,0.2)";
  const placeholder = tone === "dark" ? "rgba(255,255,255,0.4)" : "rgba(0,0,0,0.4)";
  return (
    <form onSubmit={submit} style={{ display:"grid", gap: 20, color: fg }}>
      <style>{`
        .vw-field{
          background: transparent;
          border: 0;
          border-bottom: 1px solid ${border};
          color: ${fg};
          font: 400 16px/1.4 'Inter',sans-serif;
          padding: 10px 0;
          width: 100%;
          outline: none;
          transition: border-color .2s;
        }
        .vw-field::placeholder { color: ${placeholder}; }
        .vw-field:focus { border-bottom-color: ${accent}; }
        .vw-field-lbl{
          font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase;
          color: ${placeholder}; margin-bottom: 4px; display:block;
          font-family: 'Inter', sans-serif;
        }
      `}</style>
      <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr", gap: 32 }}>
        <div>
          <label className="vw-field-lbl">{L.name}</label>
          <input className="vw-field" name="name" required />
        </div>
        <div>
          <label className="vw-field-lbl">{L.company}</label>
          <input className="vw-field" name="company" />
        </div>
        <div>
          <label className="vw-field-lbl">{L.email}</label>
          <input className="vw-field" name="email" type="email" required />
        </div>
        <div>
          <label className="vw-field-lbl">{L.type}</label>
          <select className="vw-field" style={{ appearance:"none" }}>
            {L.types.map((t, i) => <option key={i} style={{color:"#1a1814"}}>{t}</option>)}
          </select>
        </div>
      </div>
      <div>
        <label className="vw-field-lbl">{L.msg}</label>
        <textarea className="vw-field" rows={3} style={{ resize:"vertical" }} />
      </div>
      <div style={{ marginTop: 10 }}>
        <button
          type="submit"
          data-cursor="submit"
          disabled={state !== "idle"}
          style={{
            position:"relative", overflow:"hidden",
            padding: "18px 40px",
            background: state === "done" ? accent : "transparent",
            color: state === "done" ? "#0a0a0a" : fg,
            border: `1px solid ${state === "done" ? accent : border}`,
            borderRadius: 0,
            fontFamily: "'Inter', sans-serif",
            fontSize: 11, letterSpacing: "0.2em", textTransform: "uppercase",
            fontWeight: 500,
            cursor: state === "idle" ? "pointer" : "default",
            transition: "all .3s cubic-bezier(.2,.7,.3,1)",
            minWidth: 220,
          }}>
          {state === "idle" && <span>{L.submit} →</span>}
          {state === "submitting" && (
            <span style={{display:"inline-flex", alignItems:"center", gap:10}}>
              <span className="vw-spinner" style={{
                width:12, height:12, borderRadius:"50%",
                border:`1.5px solid ${fg}`, borderTopColor:"transparent",
                animation:"vw-spin 0.8s linear infinite",
                display:"inline-block"
              }}/>
              {L.sending}
            </span>
          )}
          {state === "done" && <span>✓ {L.done}</span>}
        </button>
      </div>
    </form>
  );
}

// ── ProtoFrame ──────────────────────────────────────────────────────────────
// A scoped scroll container that each variation renders into. Isolates the
// custom cursor + scroll events so we can show all three variations inside a
// design canvas without global collisions.
function ProtoFrame({ children, cursorStyle = "circle", accent = "#C9A96E", palette = {}, fontVars = {}, className = "", label, artboardSize }) {
  const ref = useRef(null);
  const { node: cursorNode } = useCursor({ containerRef: ref, style: cursorStyle, accentVar: accent });

  const paletteVars = {
    "--vw-bg":      palette.bg      || "#f6f4ef",
    "--vw-fg":      palette.fg      || "#1a1814",
    "--vw-ink":     palette.ink     || "#0A0E1A",
    "--vw-muted":   palette.muted   || "#6a6256",
    "--vw-line":    palette.line    || "rgba(10,14,26,0.15)",
    "--vw-accent":  accent,
    "--vw-highlight": palette.highlight || "#C9A96E",
    "--vw-dark":    palette.dark    || "#0A0E1A",
    "--vw-ivory":   palette.ivory   || "#F8F6F2",
    ...fontVars,
  };

  return (
    <div
      ref={ref}
      className={className + " vw-no-cursor"}
      data-proto-label={label}
      style={{
        position:"relative", width: "100%", height: "100%",
        overflowY: "auto", overflowX: "hidden",
        background: "var(--vw-bg)",
        color: "var(--vw-fg)",
        fontFamily: "var(--vw-body-font, 'Inter', sans-serif)",
        ...paletteVars,
        scrollBehavior: "smooth",
      }}
    >
      {cursorNode}
      {children}
    </div>
  );
}

// ── Global animation keyframes (injected once) ──────────────────────────────
if (typeof document !== "undefined" && !document.getElementById("vw-anim-styles")) {
  const s = document.createElement("style");
  s.id = "vw-anim-styles";
  s.textContent = `
    @keyframes vw-spin { from { transform: rotate(0deg);} to { transform: rotate(360deg);} }
    @keyframes vw-star-spin { from { transform: rotate(0deg);} to { transform: rotate(360deg);} }
    @keyframes vw-star-pulse { 0%,100% { transform: translate(-50%,-50%) scale(1); opacity: 1; } 50% { transform: translate(-50%,-50%) scale(1.6); opacity: 0.6; } }
    @keyframes vw-fade { from { opacity: 0; } to { opacity: 1; } }
    @keyframes vw-marq { from { transform: translateX(0);} to { transform: translateX(-33.333%);} }
    .vw-no-cursor input, .vw-no-cursor textarea, .vw-no-cursor select { cursor: text !important; }
    .vw-no-cursor button, .vw-no-cursor a, .vw-no-cursor [data-cursor] { cursor: none !important; }
    /* Elegant scrollbar inside proto frames */
    .vw-no-cursor::-webkit-scrollbar { width: 0; height: 0; }
  `;
  document.head.appendChild(s);
}

Object.assign(window, {
  Photo, useCursor, CounterUp, InView, StaggerText,
  Lightbox, Marquee, ContactForm, ProtoFrame, StarCursor,
});
