// ui_kits/portfolio/components.jsx
// Shared chrome: Nav, Footer, Marquee, Grain, Cursor, helpers

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

// ============================================================
// useT — i18n hook
// ============================================================
function useT(lang) {
  return window.I18N[lang] || window.I18N.en;
}

// ============================================================
// Grain — fixed full-viewport overlay
// ============================================================
function Grain() {
  return <div className="grain" aria-hidden="true" />;
}

// ============================================================
// Cursor — custom outline that scales over interactive
// ============================================================
function Cursor() {
  const dot = useRef(null);
  const ring = useRef(null);
  const label = useRef(null);
  useEffect(() => {
    let raf;
    let x = -100, y = -100, rx = -100, ry = -100;
    let big = false;
    let txt = "";
    const move = (e) => {
      x = e.clientX; y = e.clientY;
      const t = e.target.closest("[data-cursor]");
      const isLink = t && t.dataset.cursor;
      big = !!isLink;
      txt = isLink || "";
    };
    const tick = () => {
      rx += (x - rx) * 0.22;
      ry += (y - ry) * 0.22;
      if (dot.current) {
        dot.current.style.transform = `translate(${x - 5}px, ${y - 5}px)`;
      }
      if (ring.current) {
        const s = big ? 1 : 0.28;
        ring.current.style.transform = `translate(${rx - 18}px, ${ry - 18}px) scale(${s})`;
        ring.current.style.borderColor = big ? "var(--accent)" : "rgba(242,240,235,0.35)";
      }
      if (label.current) {
        label.current.style.opacity = big && txt ? "1" : "0";
        label.current.textContent = txt.toUpperCase();
        label.current.style.transform = `translate(${rx + 22}px, ${ry - 10}px)`;
      }
      raf = requestAnimationFrame(tick);
    };
    window.addEventListener("mousemove", move);
    tick();
    return () => {
      window.removeEventListener("mousemove", move);
      cancelAnimationFrame(raf);
    };
  }, []);
  // Hide on touch
  const isTouch = typeof window !== "undefined" && window.matchMedia("(hover: none)").matches;
  if (isTouch) return null;
  return (
    <div style={cursorStyles.wrap} aria-hidden="true">
      <div ref={ring} style={cursorStyles.ring} />
      <div ref={dot} style={cursorStyles.dot} />
      <div ref={label} style={cursorStyles.label} />
    </div>
  );
}
const cursorStyles = {
  wrap: { position: "fixed", inset: 0, pointerEvents: "none", zIndex: 10000 },
  ring: { position: "fixed", left: 0, top: 0, width: 36, height: 36, border: "1px solid", borderRadius: "50%", willChange: "transform" },
  dot: { position: "fixed", left: 0, top: 0, width: 10, height: 10, background: "var(--fg-1)", borderRadius: "50%", willChange: "transform" },
  label: {
    position: "fixed", left: 0, top: 0,
    fontFamily: "var(--ff-mono)", fontSize: 10, letterSpacing: "0.1em", fontWeight: 700,
    color: "var(--bg)", background: "var(--accent)",
    padding: "4px 8px",
    opacity: 0, willChange: "transform, opacity",
    transition: "opacity 140ms",
    whiteSpace: "nowrap",
  },
};

// ============================================================
// LiveClock — ticking time in footer
// ============================================================
function LiveClock({ tz = "Europe/Madrid" }) {
  const [t, setT] = useState(() => new Date());
  useEffect(() => {
    const i = setInterval(() => setT(new Date()), 1000);
    return () => clearInterval(i);
  }, []);
  const fmt = t.toLocaleTimeString("en-GB", { timeZone: tz, hour12: false });
  return <span>{fmt} CET · LIVE</span>;
}

// ============================================================
// Nav
// ============================================================
function Nav({ lang, setLang, route, go }) {
  const t = useT(lang);
  const [scrolled, setScrolled] = useState(false);
  useEffect(() => {
    const onS = () => setScrolled(window.scrollY > 80);
    window.addEventListener("scroll", onS);
    return () => window.removeEventListener("scroll", onS);
  }, []);
  return (
    <nav style={{ ...navStyles.nav, ...(scrolled ? navStyles.scrolled : {}) }}>
      <a href="#" data-cursor="home" onClick={(e) => { e.preventDefault(); go("home"); }} style={navStyles.mark}>
        <span style={navStyles.monogram}>EL/</span>
        <span style={navStyles.role}>{t.role}</span>
      </a>
      <div style={navStyles.links}>
        {[["home", t.nav.home, "001"], ["archive", t.nav.archive, "002"], ["about", t.nav.about, "003"]].map(([k, lbl, n]) => (
          <a key={k} href="#" data-cursor={k} onClick={(e) => { e.preventDefault(); go(k); }} style={{ ...navStyles.link, color: route === k ? "var(--fg-1)" : "var(--fg-2)" }}>
            <span style={{ color: "var(--fg-3)", marginRight: 6 }}>{n}</span>{lbl}
          </a>
        ))}
      </div>
      <div style={navStyles.right}>
        <div style={navStyles.lang}>
          <button data-cursor="en" onClick={() => setLang("en")} style={{ ...navStyles.langBtn, color: lang === "en" ? "var(--fg-1)" : "var(--fg-3)" }}>EN</button>
          <span style={{ color: "var(--fg-3)" }}>·</span>
          <button data-cursor="es" onClick={() => setLang("es")} style={{ ...navStyles.langBtn, color: lang === "es" ? "var(--fg-1)" : "var(--fg-3)" }}>ES</button>
        </div>
        <div style={navStyles.status}>
          <span style={navStyles.dot} />
          {t.status_available.split(" — ")[0]}
        </div>
      </div>
    </nav>
  );
}
const navStyles = {
  nav: {
    position: "sticky", top: 0, zIndex: 100,
    display: "flex", alignItems: "center", justifyContent: "space-between",
    padding: "16px 48px",
    borderBottom: "1px solid var(--rule)",
    background: "rgba(10,10,11,0.7)", backdropFilter: "blur(12px)",
    fontFamily: "var(--ff-mono)",
    height: "var(--nav-h)",
    boxSizing: "border-box",
  },
  scrolled: { background: "rgba(10,10,11,0.85)" },
  mark: { display: "flex", alignItems: "center", gap: 12, textDecoration: "none" },
  monogram: { fontFamily: "var(--ff-display)", fontWeight: 700, fontSize: 20, letterSpacing: "-0.04em", color: "var(--fg-1)", transform: "scaleX(0.92)", transformOrigin: "left" },
  role: { fontSize: 10, color: "var(--fg-3)", letterSpacing: "0.08em", textTransform: "uppercase" },
  links: { display: "flex", gap: 28, fontSize: 12, letterSpacing: "0.06em", textTransform: "uppercase" },
  link: { textDecoration: "none", transition: "color 140ms" },
  right: { display: "flex", gap: 18, alignItems: "center" },
  lang: { display: "flex", alignItems: "center", gap: 4, fontSize: 11, letterSpacing: "0.08em", textTransform: "uppercase" },
  langBtn: { background: "none", border: 0, padding: 0, fontFamily: "inherit", fontSize: "inherit", letterSpacing: "inherit", cursor: "pointer" },
  status: { fontSize: 10, color: "var(--fg-2)", letterSpacing: "0.08em", textTransform: "uppercase", display: "flex", alignItems: "center", gap: 8 },
  dot: { width: 6, height: 6, background: "var(--ok)", borderRadius: "50%", boxShadow: "0 0 0 3px rgba(125,224,166,0.18)" },
};

// ============================================================
// Footer
// ============================================================
function Footer({ lang }) {
  const t = useT(lang);
  return (
    <footer style={footerStyles.f}>
      <div style={footerStyles.row}>
        <div>{t.footer.since}</div>
        <div>{t.footer.madrid}</div>
        <div><LiveClock /></div>
      </div>
    </footer>
  );
}
const footerStyles = {
  f: { padding: "28px 48px", borderTop: "1px solid var(--rule)", fontFamily: "var(--ff-mono)", marginTop: "var(--s-8)" },
  row: { display: "flex", justifyContent: "space-between", fontSize: 11, letterSpacing: "0.06em", textTransform: "uppercase", color: "var(--fg-3)" },
};

// ============================================================
// Marquee — items: {text, color}. color keys map to CSS vars.
// ============================================================
const MARQUEE_COLORS = {
  fg: "var(--fg-1)",
  blue: "var(--accent)",
  red: "var(--bad)",
  green: "var(--ok)",
  amber: "var(--accent-hi)",
};
function Marquee({ items }) {
  const norm = items.map((it) => typeof it === "string" ? { text: it, color: "fg" } : it);
  const list = [...norm, ...norm, ...norm, ...norm];
  return (
    <div className="marquee">
      <div className="marquee__track">
        {list.map((it, i) => (
          <React.Fragment key={i}>
            <span style={{ fontFamily: "var(--ff-display)", fontWeight: 700, fontSize: 28, letterSpacing: "-0.02em", color: MARQUEE_COLORS[it.color] || "var(--fg-1)" }}>{it.text}</span>
            <span style={{ color: "var(--fg-3)", fontSize: 28 }}>×</span>
          </React.Fragment>
        ))}
      </div>
    </div>
  );
}

// ============================================================
// PageTransition — masks route changes with a brief bg flash + slide
// ============================================================
function PageTransition({ pageKey, children }) {
  const [k, setK] = useState(pageKey);
  const [phase, setPhase] = useState("in"); // 'out' | 'in'
  useEffect(() => {
    if (pageKey === k) return;
    setPhase("out");
    const t1 = setTimeout(() => {
      setK(pageKey);
      setPhase("in");
      window.scrollTo({ top: 0, behavior: "instant" });
      // Two-frame entry: out → off, then in next frame for fresh transition
      requestAnimationFrame(() => requestAnimationFrame(() => setPhase("in")));
    }, 240);
    return () => clearTimeout(t1);
  }, [pageKey, k]);
  return (
    <div style={{
      opacity: phase === "out" ? 0 : 1,
      transform: phase === "out" ? "translateY(12px)" : "translateY(0)",
      filter: phase === "out" ? "blur(6px)" : "blur(0)",
      transition: "opacity 240ms cubic-bezier(.7,0,.3,1), transform 240ms cubic-bezier(.7,0,.3,1), filter 240ms cubic-bezier(.7,0,.3,1)",
    }}>
      {React.cloneElement(children, { _pkey: k })}
    </div>
  );
}

// ============================================================
// Reveal — instant opacity/transform snap on mount after `delay` ms.
// NO CSS transitions — they freeze in the iframe environment.
// Staggered delays on sibling Reveals give choreography.
// ============================================================
function Reveal({ children, delay = 0, y = 24, as: Tag = "div", ...rest }) {
  const [shown, setShown] = useState(false);
  useEffect(() => {
    const t = setTimeout(() => setShown(true), Math.max(20, delay));
    return () => clearTimeout(t);
  }, [delay]);
  return (
    <Tag {...rest} style={{
      opacity: shown ? 1 : 0,
      transform: shown ? "none" : `translateY(${y}px)`,
      ...(rest.style || {}),
    }}>
      {children}
    </Tag>
  );
}

// ============================================================
// SplitText — word-by-word reveal; for hero titles
// ============================================================
function SplitText({ children, delay = 0, stagger = 60 }) {
  const text = String(children);
  return (
    <span aria-label={text}>
      {text.split(/(\s+)/).map((part, i) => {
        if (/^\s+$/.test(part)) return <span key={i}>{part}</span>;
        return (
          <span key={i} style={{ display: "inline-block", overflow: "hidden", verticalAlign: "bottom", paddingBottom: "0.05em", marginBottom: "-0.05em" }}>
            <span style={{
              display: "inline-block",
              animation: `splitUp 700ms cubic-bezier(.2,.7,0,1) ${delay + i * stagger}ms both`,
              transform: "translateY(110%)",
            }}>{part}</span>
          </span>
        );
      })}
    </span>
  );
}

// ============================================================
// Helpers
// ============================================================
function formatDate(dateStr, lang) {
  const d = new Date(dateStr);
  const y = d.getFullYear();
  const m = String(d.getMonth() + 1).padStart(2, "0");
  const day = String(d.getDate()).padStart(2, "0");
  return lang === "es" ? `${day}.${m}.${y}` : `${y}.${m}.${day}`;
}

function tx(obj, lang) {
  if (typeof obj === "string") return obj;
  return obj?.[lang] ?? obj?.en ?? "";
}

// ============================================================
// Export to window
// ============================================================
Object.assign(window, {
  Grain, Cursor, Nav, Footer, Marquee, PageTransition, LiveClock, Reveal, SplitText,
  useT, formatDate, tx,
});
