/* Shared hooks + small components (attached to window) */
const { useState, useEffect, useRef } = React;

/* Reveal-on-scroll wrapper */
const Reveal = ({ as: Tag = "div", delay = 0, className = "", children, ...p }) => {
  const ref = useRef(null);
  const [show, setShow] = useState(false);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver(
      ([e]) => { if (e.isIntersecting) { setShow(true); io.disconnect(); } },
      { threshold: 0.12, rootMargin: "0px 0px -40px 0px" }
    );
    io.observe(el);
    return () => io.disconnect();
  }, []);
  const d = delay ? ` d${delay}` : "";
  return <Tag ref={ref} className={`reveal${d} ${show ? "in" : ""} ${className}`} {...p}>{children}</Tag>;
};

/* Count-up number when visible */
const CountUp = ({ value }) => {
  const ref = useRef(null);
  const [txt, setTxt] = useState("0");
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    // parse number, keep separators
    const target = parseFloat(value.replace(/[^\d,.-]/g, "").replace(/\./g, "").replace(",", ".")) || 0;
    const io = new IntersectionObserver(([e]) => {
      if (!e.isIntersecting) return;
      io.disconnect();
      const dur = 1400, t0 = performance.now();
      const fmt = (n) => {
        const r = Math.round(n);
        return value.includes(".") ? r.toLocaleString("id-ID") : String(r);
      };
      const tick = (t) => {
        const k = Math.min(1, (t - t0) / dur);
        const e2 = 1 - Math.pow(1 - k, 3);
        setTxt(fmt(target * e2));
        if (k < 1) requestAnimationFrame(tick);
      };
      requestAnimationFrame(tick);
    }, { threshold: 0.4 });
    io.observe(el);
    return () => io.disconnect();
  }, [value]);
  return <span ref={ref}>{txt}</span>;
};

window.Reveal = Reveal;
window.CountUp = CountUp;

/* Paginated list controller: returns {page, setPage, pageItems, pages, total, range} */
const usePaged = (items, perPage, deps = []) => {
  const [page, setPage] = useState(1);
  const pages = Math.max(1, Math.ceil(items.length / perPage));
  useEffect(() => { setPage(1); }, deps); // reset when deps (e.g. filter) change
  const safe = Math.min(page, pages);
  const start = (safe - 1) * perPage;
  const pageItems = items.slice(start, start + perPage);
  return { page: safe, setPage, pageItems, pages, total: items.length, from: items.length ? start + 1 : 0, to: Math.min(start + perPage, items.length) };
};

/* Pager UI with windowed page numbers + ellipses */
const Pager = ({ page, pages, onChange }) => {
  if (pages <= 1) return null;
  const nums = [];
  for (let i = 1; i <= pages; i++) {
    if (i === 1 || i === pages || Math.abs(i - page) <= 1) nums.push(i);
    else if (nums[nums.length - 1] !== "…") nums.push("…");
  }
  const goto = (n) => { onChange(n); };
  return (
    <div className="pager" role="navigation" aria-label="Halaman">
      <button className="pg-arrow" disabled={page === 1} onClick={() => goto(page - 1)} aria-label="Sebelumnya">
        <Icon name="arrow" style={{ transform: "rotate(180deg)" }} />
      </button>
      {nums.map((n, i) => n === "…"
        ? <span key={"d" + i} className="pg-dots">…</span>
        : <button key={n} className={"pg-num" + (n === page ? " active" : "")} onClick={() => goto(n)} aria-current={n === page ? "page" : undefined}>{n}</button>
      )}
      <button className="pg-arrow" disabled={page === pages} onClick={() => goto(page + 1)} aria-label="Berikutnya">
        <Icon name="arrow" />
      </button>
    </div>
  );
};

window.usePaged = usePaged;
window.Pager = Pager;
