/* global React */
const { useState, useEffect, useRef } = React;

/* ---------- tiny icon set ---------- */
const Icon = {
  copy: (p) => (<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>),
  check: (p) => (<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" {...p}><polyline points="20 6 9 17 4 12"/></svg>),
  play: (p) => (<svg viewBox="0 0 24 24" fill="currentColor" {...p}><path d="M8 5v14l11-7z"/></svg>),
  yt: (p) => (<svg viewBox="0 0 24 24" fill="currentColor" {...p}><path d="M23 12s0-3.8-.5-5.6a3 3 0 0 0-2.1-2.1C18.6 3.8 12 3.8 12 3.8s-6.6 0-8.4.5a3 3 0 0 0-2.1 2.1C1 8.2 1 12 1 12s0 3.8.5 5.6a3 3 0 0 0 2.1 2.1c1.8.5 8.4.5 8.4.5s6.6 0 8.4-.5a3 3 0 0 0 2.1-2.1C23 15.8 23 12 23 12zM9.8 15.5v-7l6 3.5z"/></svg>),
  tt: (p) => (<svg viewBox="0 0 24 24" fill="currentColor" {...p}><path d="M16.5 3c.4 2.4 1.9 4.1 4.2 4.4v2.7c-1.4.1-2.7-.3-4.1-1v6.3c0 4-2.9 6.6-6.4 6.6A6.1 6.1 0 0 1 4 16.3c0-3.6 3.2-6.2 7-5.6v2.9c-.4-.1-.9-.2-1.4-.2-1.6 0-2.9 1.2-2.9 2.8s1.3 2.9 2.9 2.9c1.7 0 3-1.3 3-3V3z"/></svg>),
  bolt: (p) => (<svg viewBox="0 0 24 24" fill="currentColor" {...p}><path d="M13 2L3 14h7l-1 8 10-12h-7z"/></svg>),
  arrow: (p) => (<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round" {...p}><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>),
};

/* skull mark: simple geometric, used as the brand glyph */
function Skull({ size = 30, ...p }) {
  return (
    <svg width={size} height={size} viewBox="0 0 32 32" fill="none" {...p}>
      <path d="M16 3C9.4 3 5 7.6 5 13.6c0 3.3 1.5 5.6 3.4 7v3.1c0 1 .8 1.8 1.8 1.8h1.1v1.7c0 .8.6 1.4 1.4 1.4h.2c.8 0 1.4-.6 1.4-1.4v-1.7h3.4v1.7c0 .8.6 1.4 1.4 1.4h.2c.8 0 1.4-.6 1.4-1.4v-1.7h1.1c1 0 1.8-.8 1.8-1.8v-3.1c1.9-1.4 3.4-3.7 3.4-7C27 7.6 22.6 3 16 3Z" fill="currentColor"/>
      <circle cx="11.5" cy="14" r="2.6" fill="#08080a"/>
      <circle cx="20.5" cy="14" r="2.6" fill="#08080a"/>
      <path d="M16 18.5l-1.3 2.4h2.6L16 18.5Z" fill="#08080a"/>
    </svg>
  );
}

/* ---------- scroll reveal ---------- */
function useReveal() {
  useEffect(() => {
    const els = document.querySelectorAll('.reveal');
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => { if (e.isIntersecting) { e.target.classList.add('in'); io.unobserve(e.target); } });
    }, { threshold: 0.15 });
    els.forEach((el) => io.observe(el));
    return () => io.disconnect();
  });
}

/* ---------- count-up ---------- */
function CountUp({ value, suffix = '', dur = 1400 }) {
  const [n, setN] = useState(0);
  const ref = useRef(null);
  const done = useRef(false);
  useEffect(() => {
    const el = ref.current;
    const io = new IntersectionObserver((ents) => {
      ents.forEach((e) => {
        if (e.isIntersecting && !done.current) {
          done.current = true;
          const start = performance.now();
          const tick = (t) => {
            const p = Math.min((t - start) / dur, 1);
            const eased = 1 - Math.pow(1 - p, 3);
            setN(value * eased);
            if (p < 1) requestAnimationFrame(tick);
          };
          requestAnimationFrame(tick);
        }
      });
    }, { threshold: 0.4 });
    if (el) io.observe(el);
    return () => io.disconnect();
  }, [value]);
  const fmt = (x) => {
    if (value >= 1e6) return (x / 1e6).toFixed(x >= 9.95e5 ? 0 : 1).replace(/\.0$/, '') + 'M';
    if (value >= 1000) return (x / 1000).toFixed(x >= 999.5 ? 2 : 1).replace(/\.0$/, '') + 'K';
    return Math.round(x).toString();
  };
  return <span ref={ref}>{fmt(n)}{suffix}</span>;
}

/* ---------- in-view, driven by React state so re-renders keep it ---------- */
function useInView(threshold = 0.15) {
  const ref = useRef(null);
  const [inView, setInView] = useState(false);
  useEffect(() => {
    const el = ref.current;
    if (!el || inView) return;
    const io = new IntersectionObserver(([e]) => {
      if (e.isIntersecting) { setInView(true); io.disconnect(); }
    }, { threshold });
    io.observe(el);
    return () => io.disconnect();
  }, []);
  return [ref, inView];
}

/* ---------- live viewers counter ---------- */
/* Pings /api/heartbeat every 10s and shows how many people are viewing right now. */
function LiveViewers() {
  const [count, setCount] = useState(null);
  useEffect(() => {
    // One stable id per browser tab so we count people, not pings.
    let id;
    try {
      id = sessionStorage.getItem('testol-vid');
      if (!id) {
        id = 'v-' + Date.now().toString(36) + '-' + Math.random().toString(36).slice(2, 9);
        sessionStorage.setItem('testol-vid', id);
      }
    } catch (e) {
      id = 'v-' + Math.random().toString(36).slice(2, 9);
    }

    let alive = true;
    const ping = async () => {
      try {
        const r = await fetch('/api/heartbeat?id=' + encodeURIComponent(id), { cache: 'no-store' });
        const d = await r.json();
        if (!alive) return;
        setCount(typeof d.count === 'number' ? d.count : null);
      } catch (e) {
        if (alive) setCount(null);
      }
    };

    ping();
    const iv = setInterval(ping, 10000);
    const onVis = () => { if (document.visibilityState === 'visible') ping(); };
    document.addEventListener('visibilitychange', onVis);
    return () => {
      alive = false;
      clearInterval(iv);
      document.removeEventListener('visibilitychange', onVis);
    };
  }, []);

  // Hide entirely until the counter is live (e.g. before the DB is connected).
  if (count === null) return null;

  return (
    <span className="live-viewers" title="People viewing the hub right now">
      <span className="live-dot" />
      <b>{count.toLocaleString()}</b> watching
    </span>
  );
}

/* ============================================================ NAV */
function Nav() {
  return (
    <nav className="nav">
      <div className="wrap nav-inner">
        <div className="brand" onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })}>
          <span className="brand-skull"><Skull size={28} /></span>
          <span className="brand-name">TESTOL<span className="dot">.</span>HUB</span>
        </div>
        <div className="nav-links">
          <a href="#scripts">Scripts</a>
          <a href="#execute">How to run</a>
          <a href="#stats">Channel</a>
          <a href="#faq">FAQ</a>
        </div>
        <div className="nav-actions">
          <LiveViewers />
          <a className="btn btn-sm btn-ghost btn-yt" href="https://www.youtube.com/@testaccountlol4465" target="_blank" rel="noopener"><Icon.yt /> Subscribe</a>
          <a className="btn btn-sm btn-accent" href="#scripts">Get scripts</a>
        </div>
      </div>
    </nav>
  );
}

/* ============================================================ HERO */
function Hero() {
  return (
    <section className="hero">
      <Skull className="hero-bg-skull" size={620} />
      <div className="wrap hero-grid">
        <div className="reveal in">
          <span className="hero-tag"><span className="live-dot" /> MM2 Based Content · 100% Keyless</span>
          <h1 className="display">
            <span className="chrome">TESTOL HUB</span>
            <span className="sub">free MM2 scripts. copy &amp; run.</span>
          </h1>
          <p className="hero-lede">
            Welcome to my hub. Every script from my channel lives here: item spawners, dupes, autofarm and more.
            No keys, no checkpoints, no nonsense. Paste it into your executor and go.
          </p>
          <div className="hero-cta">
            <a className="btn btn-accent" href="#scripts"><Icon.bolt /> Get the scripts</a>
            <a className="btn btn-ghost" href="https://www.youtube.com/@testaccountlol4465" target="_blank" rel="noopener"><Icon.play /> Watch on YouTube</a>
          </div>
          <div className="hero-trust">
            <span className="live-dot"></span>
            Trusted by <b>2,800+</b> MM2 players &amp; counting
          </div>
        </div>

        <div className="creator-card reveal in">
          <div className="creator-top">
            <div className="avatar">
              <image-slot id="pfp" shape="circle" src="pfp.png" placeholder="Drop your pfp"></image-slot>
            </div>
            <div>
              <div className="creator-name">testol yfm</div>
              <div className="creator-handle">@testaccountlol4465</div>
            </div>
          </div>
          <div className="creator-stats">
            <div className="cstat"><div className="num">2.88K</div><div className="lbl">Subs</div></div>
            <div className="cstat"><div className="num">77</div><div className="lbl">Videos</div></div>
            <div className="cstat"><div className="num">MM2</div><div className="lbl">Niche</div></div>
          </div>
          <div className="creator-foot">
            <a className="btn btn-sm btn-yt" href="https://www.youtube.com/@testaccountlol4465" target="_blank" rel="noopener"><Icon.yt /> YouTube</a>
            <a className="btn btn-sm btn-tt" href="https://www.tiktok.com/@testolscripts" target="_blank" rel="noopener"><Icon.tt /> TikTok</a>
          </div>
        </div>
      </div>
    </section>
  );
}

Object.assign(window, { Icon, Skull, Nav, Hero, CountUp, useReveal, useInView });
