/* ui.jsx — primitives, icons, battery motif, nav */
const { useState, useEffect, useRef, useCallback } = React;

/* ---------- icons (simple, geometric, no AI-flourish) ---------- */
function Icon({ d, size = 18, stroke = 1.6, fill = "none" }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill={fill}
         stroke="currentColor" strokeWidth={stroke} strokeLinecap="round"
         strokeLinejoin="round" aria-hidden="true">
      {d}
    </svg>
  );
}
const IconLinkedIn = (p) => (
  <Icon size={p.size} d={<g><rect x="3" y="3" width="18" height="18" rx="2"/><line x1="7.5" y1="10.5" x2="7.5" y2="16.5"/><circle cx="7.5" cy="7.4" r="0.6" fill="currentColor" stroke="none"/><path d="M11 16.5v-3.2a2 2 0 0 1 4 0v3.2"/><line x1="11" y1="10.8" x2="11" y2="16.5"/></g>} />
);
const IconGitHub = (p) => (
  <Icon size={p.size} d={<path d="M9 19c-4 1.2-4-2-5.5-2.5M15 21v-3.2a2.8 2.8 0 0 0-.8-2.2c2.6-.3 5.3-1.3 5.3-5.8a4.5 4.5 0 0 0-1.2-3.1 4.2 4.2 0 0 0-.1-3.1s-1-.3-3.3 1.2a11.4 11.4 0 0 0-6 0C6.6 1 5.6 1.3 5.6 1.3a4.2 4.2 0 0 0-.1 3.1A4.5 4.5 0 0 0 4.3 7.5c0 4.5 2.7 5.5 5.3 5.8a2.8 2.8 0 0 0-.8 2.1V21" />} />
);
const IconArrow = (p) => (
  <Icon size={p.size || 18} d={<g><line x1="5" y1="12" x2="19" y2="12"/><polyline points="13 6 19 12 13 18"/></g>} />
);
const IconDownload = (p) => (
  <Icon size={p.size || 18} d={<g><path d="M12 3v12"/><polyline points="7 11 12 16 17 11"/><path d="M5 20h14"/></g>} />
);
const IconClose = (p) => (
  <Icon size={p.size || 20} d={<g><line x1="6" y1="6" x2="18" y2="18"/><line x1="18" y1="6" x2="6" y2="18"/></g>} />
);

/* ---------- battery / charge motif ---------- */
/* A column of cell segments that "charge up" — the signature touch. */
function ChargeColumn({ segments = 7, filled = 5, vertical = true, animate = true }) {
  const [lit, setLit] = useState(animate ? 0 : filled);
  useEffect(() => {
    if (!animate) { setLit(filled); return; }
    let n = 0;
    setLit(0);
    const t = setInterval(() => {
      n += 1;
      setLit(n);
      if (n >= filled) clearInterval(t);
    }, 130);
    return () => clearInterval(t);
  }, [filled, animate]);
  return (
    <div className={"charge-col " + (vertical ? "v" : "h")} aria-hidden="true">
      {Array.from({ length: segments }).map((_, i) => (
        <span key={i} className={"seg" + (i < lit ? " on" : "")}
              style={{ transitionDelay: (i * 30) + "ms" }} />
      ))}
    </div>
  );
}

/* thin battery glyph with a fill level */
function BatteryGlyph({ level = 0.72, w = 46 }) {
  return (
    <span className="battery-glyph" style={{ width: w }}>
      <span className="bg-body">
        <span className="bg-fill" style={{ width: Math.round(level * 100) + "%" }} />
      </span>
      <span className="bg-cap" />
    </span>
  );
}

/* ---------- reveal-on-scroll ---------- */
function Reveal({ children, as: Tag = "div", className = "", delay = 0, y = 18, ...rest }) {
  const ref = useRef(null);
  const [shown, setShown] = useState(false);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    let done = false;
    const reveal = () => { if (!done) { done = true; setShown(true); } };

    // 1) if already within (or near) the viewport on mount, reveal right away
    const inView = () => {
      const r = el.getBoundingClientRect();
      const vh = window.innerHeight || document.documentElement.clientHeight;
      return r.top < vh * 0.94 && r.bottom > 0;
    };
    if (inView()) {
      const id = requestAnimationFrame(reveal);
      return () => cancelAnimationFrame(id);
    }

    // 2) otherwise observe for scroll-in, with a hard fallback so content
    //    can never get stuck invisible if IO never fires in this frame.
    let obs;
    if ("IntersectionObserver" in window) {
      obs = new IntersectionObserver((entries) => {
        entries.forEach((e) => { if (e.isIntersecting) reveal(); });
      }, { threshold: 0.1, rootMargin: "0px 0px -6% 0px" });
      obs.observe(el);
    }
    const onScroll = () => { if (inView()) reveal(); };
    window.addEventListener("scroll", onScroll, { passive: true });
    const fallback = setTimeout(reveal, 850);
    return () => {
      if (obs) obs.disconnect();
      window.removeEventListener("scroll", onScroll);
      clearTimeout(fallback);
    };
  }, []);
  useEffect(() => { if (shown && ref.current) ref.current.classList.add("in"); }, [shown]);
  return (
    <Tag ref={ref} className={"reveal " + (shown ? "in " : "") + className}
         style={{ transitionDelay: delay + "ms", "--ry": y + "px" }} {...rest}>
      {children}
    </Tag>
  );
}

/* ---------- small bits ---------- */
function Kicker({ children, num }) {
  return (
    <div className="kicker">
      {num != null && <span className="kicker-num">{num}</span>}
      <span className="kicker-line" />
      <span className="kicker-text">{children}</span>
    </div>
  );
}

function Tag({ children, active, onClick, as = "span" }) {
  const Comp = as;
  return (
    <Comp className={"tag" + (active ? " active" : "")} onClick={onClick}>
      {children}
    </Comp>
  );
}

/* ---------- nav ---------- */
const NAV = [
  { id: "home", label: "Home" },
  { id: "work", label: "Work" },
  { id: "experience", label: "Experience" },
  { id: "interests", label: "Interests" },
];

function Nav({ route, onRoute, person, progress }) {
  return (
    <header className="nav">
      <div className="nav-inner">
        <button className="brand" onClick={() => onRoute("home")}>
          <span className="brand-mark">
            <BatteryGlyph level={0.78} w={30} />
          </span>
          <span className="brand-name">{person.name}</span>
        </button>

        <nav className="nav-links">
          {NAV.map((n) => (
            <button key={n.id}
              className={"nav-link" + (route === n.id ? " current" : "")}
              onClick={() => onRoute(n.id)}>
              <span>{n.label}</span>
              <span className="nav-underline" />
            </button>
          ))}
        </nav>

        <div className="nav-actions">
          <a className="ghost-icon" href={person.links.linkedin} target="_blank" rel="noreferrer" aria-label="LinkedIn"><IconLinkedIn size={17} /></a>
          <a className="ghost-icon" href={person.links.github} target="_blank" rel="noreferrer" aria-label="GitHub"><IconGitHub size={17} /></a>
          <a className="btn small" href={person.resume} target="_blank" rel="noreferrer">
            <IconDownload size={15} /> <span>{person.resumeLabel}</span>
          </a>
        </div>
      </div>
      <div className="nav-progress"><span style={{ transform: `scaleX(${progress})` }} /></div>
    </header>
  );
}

Object.assign(window, {
  Icon, IconLinkedIn, IconGitHub, IconArrow, IconDownload, IconClose,
  ChargeColumn, BatteryGlyph, Reveal, Kicker, Tag, Nav, NAV,
});
