// Shared UI pieces — nav, footer, hero variants, helpers.

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

const NAV = [
  { path: '/', label: 'Home' },
  { path: '/podcast', label: 'Podcast' },
  { path: '/journal', label: 'Journal' },
  { path: '/gear', label: 'Gear' },
  { path: '/newsletter', label: 'The Gravel Loop' },
  { path: '/events', label: 'Events' },
  { path: '/membership', label: 'Membership' },
  { path: '/about', label: 'About' },
  { path: '/contact', label: 'Contact' }
];

// External presence — single source of truth for off-site links.
const SOCIAL = {
  apple:     'https://podcasts.apple.com/ca/podcast/velo-health/id1859510634',
  spotify:   'https://open.spotify.com/show/31XA0zxf3eoy9LdWQgqD9P',
  youtube:   'https://www.youtube.com/@VeloHealthLtd',
  rss:       'https://anchor.fm/s/10c914af8/podcast/rss',
  instagram: 'https://www.instagram.com/thegravelloop/'
};

function useRoute() {
  const [path, setPath] = useState(() => window.location.hash.replace(/^#/, '') || '/');
  useEffect(() => {
    const handler = () => setPath(window.location.hash.replace(/^#/, '') || '/');
    window.addEventListener('hashchange', handler);
    return () => window.removeEventListener('hashchange', handler);
  }, []);
  return [path, (p) => { window.location.hash = p; window.scrollTo(0, 0); }];
}

function Link({ to, children, className, ...rest }) {
  return (
    <a href={'#' + to} className={className} {...rest}>{children}</a>
  );
}

// Any "Subscribe" CTA should land the visitor on the actual signup form, from
// anywhere on the site. The app owns the URL hash for routing, so we can't use
// a plain #subscribe anchor — scroll + focus the form in JS instead.
function goToSubscribe(e) {
  if (e && e.preventDefault) e.preventDefault();
  const focusForm = () => {
    const el = document.getElementById('subscribe');
    if (!el) return false;
    el.scrollIntoView({ behavior: 'smooth', block: 'start' });
    const input = el.querySelector('input[type="email"]');
    if (input) setTimeout(() => { try { input.focus({ preventScroll: true }); } catch (_) {} }, 500);
    return true;
  };
  // If the current page already has the signup form, just go to it.
  if (focusForm()) return;
  // Otherwise route to the newsletter page, then scroll once it renders.
  window.location.hash = '/newsletter';
  let tries = 0;
  const timer = setInterval(() => {
    if (focusForm() || ++tries > 30) clearInterval(timer);
  }, 50);
}

function Topbar({ path }) {
  const [menuOpen, setMenuOpen] = useState(false);

  // Close the mobile menu whenever the route changes (link tapped, back button).
  useEffect(() => { setMenuOpen(false); }, [path]);

  // While the menu is open, lock body scroll and allow Escape to close it.
  useEffect(() => {
    if (!menuOpen) return;
    const prev = document.body.style.overflow;
    document.body.style.overflow = 'hidden';
    const onKey = (e) => { if (e.key === 'Escape') setMenuOpen(false); };
    window.addEventListener('keydown', onKey);
    return () => {
      document.body.style.overflow = prev;
      window.removeEventListener('keydown', onKey);
    };
  }, [menuOpen]);

  const items = NAV.filter(n => n.label !== 'Home');

  return (
    <header className={'topbar' + (menuOpen ? ' menu-open' : '')}>
      <div className="wrap topbar-inner">
        <Link to="/" className="brand">
          <span className="brand-mark">V</span>
          <span>Velo Health</span>
        </Link>
        <nav className="nav-links">
          {items.map(n => (
            <Link key={n.path} to={n.path} className={path === n.path ? 'active' : ''}>{n.label}</Link>
          ))}
        </nav>
        <Link to="/newsletter" className="nav-cta" onClick={goToSubscribe}>Subscribe</Link>
        <button
          type="button"
          className="nav-toggle"
          aria-label={menuOpen ? 'Close menu' : 'Open menu'}
          aria-expanded={menuOpen}
          aria-controls="mobile-menu"
          onClick={() => setMenuOpen(o => !o)}
        >
          <span className="nav-toggle-bars" aria-hidden="true"><i /><i /><i /></span>
        </button>
      </div>

      <div
        id="mobile-menu"
        className={'mobile-menu' + (menuOpen ? ' open' : '')}
      >
        <nav className="mobile-menu-links">
          {NAV.map(n => (
            <Link
              key={n.path}
              to={n.path}
              className={path === n.path ? 'active' : ''}
              onClick={() => setMenuOpen(false)}
            >
              {n.label}
            </Link>
          ))}
        </nav>
        <Link
          to="/newsletter"
          className="mobile-menu-cta"
          onClick={(e) => { setMenuOpen(false); goToSubscribe(e); }}
        >
          Subscribe <span className="arrow">→</span>
        </Link>
      </div>
      <button
        type="button"
        className={'mobile-menu-scrim' + (menuOpen ? ' open' : '')}
        aria-hidden="true"
        tabIndex={-1}
        onClick={() => setMenuOpen(false)}
      />
    </header>
  );
}

function Footer() {
  return (
    <footer>
      <div className="wrap">
        <div className="foot-grid">
          <div>
            <div className="foot-brand">Velo Health</div>
            <div style={{ maxWidth: '34ch', color: 'var(--muted)' }}>
              Independent gravel cycling media, community, and commerce. Toronto &amp; everywhere the road turns to dust.
            </div>
            <div className="foot-disclaimer">
              Velo Health Ltd. is a gravel cycling media brand. Our content is general, educational, and for entertainment. It is not medical advice, not a training plan, and not a substitute for talking to your own healthcare providers.
            </div>
          </div>
          <div>
            <h5>Read</h5>
            <ul>
              <li><Link to="/podcast">Podcast</Link></li>
              <li><Link to="/journal">Journal</Link></li>
              <li><Link to="/gear">Gear</Link></li>
              <li><Link to="/newsletter">The Gravel Loop</Link></li>
            </ul>
          </div>
          <div>
            <h5>Ride</h5>
            <ul>
              <li><Link to="/events">Events</Link></li>
              <li><Link to="/membership">Membership</Link></li>
              <li><Link to="/about">About</Link></li>
              <li><Link to="/contact">Contact</Link></li>
            </ul>
          </div>
          <div>
            <h5>Elsewhere</h5>
            <ul>
              <li><a href={SOCIAL.instagram} target="_blank" rel="noreferrer">Instagram</a></li>
              <li><a href={SOCIAL.youtube} target="_blank" rel="noreferrer">YouTube</a></li>
              <li><a href={SOCIAL.apple} target="_blank" rel="noreferrer">Apple Podcasts</a></li>
              <li><a href={SOCIAL.spotify} target="_blank" rel="noreferrer">Spotify</a></li>
              <li><a href={SOCIAL.rss} target="_blank" rel="noreferrer">RSS</a></li>
            </ul>
          </div>
        </div>
        <div className="foot-legal">
          <span>© 2026 Velo Health Ltd. · Ontario, Canada</span>
          <span>Gear. Grit. Gravel.</span>
        </div>
      </div>
    </footer>
  );
}

// Newsletter block, reused across pages
// Shared, memoized so multiple NewsletterBlocks on a page make one request.
let _subCountPromise;
function getSubscriberCount() {
  if (!_subCountPromise) {
    _subCountPromise = fetch('/api/subscribers')
      .then(r => (r.ok ? r.json() : null))
      .then(d => (d && typeof d.count === 'number' ? d.count : null))
      .catch(() => null);
  }
  return _subCountPromise;
}

function NewsletterBlock() {
  const [email, setEmail] = useState('');
  const [name, setName] = useState('');
  const [status, setStatus] = useState('idle'); // idle | sending | done | error
  const [count, setCount] = useState(null);

  useEffect(() => {
    let live = true;
    getSubscriberCount().then(c => { if (live) setCount(c); });
    return () => { live = false; };
  }, []);

  const submit = async (e) => {
    e.preventDefault();
    if (status === 'sending') return;
    setStatus('sending');
    try {
      const r = await fetch('/api/subscribe', {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ email, name })
      });
      const d = await r.json().catch(() => ({}));
      setStatus(r.ok && d.ok ? 'done' : 'error');
    } catch {
      setStatus('error');
    }
  };

  const label = status === 'sending' ? 'Subscribing…'
    : status === 'done' ? 'Thanks — check your inbox ↗'
    : status === 'error' ? 'Try again →'
    : 'Subscribe →';

  return (
    <section className="newsletter" id="subscribe">
      <div className="newsletter-inner">
        <div>
          <div className="eyebrow">The Gravel Loop</div>
          <h2>Product reviews, every other Friday.</h2>
          <p>A newsletter for gear that earns its place. Long-term notes on the bikes, tires, kit, and tools we actually ride. One email. No spam. No press-release paraphrase.</p>
        </div>
        <form className="newsletter-form" onSubmit={submit}>
          <div>
            <label>Name</label>
            <input type="text" placeholder="First name" value={name} onChange={e => setName(e.target.value)} />
          </div>
          <div>
            <label>Email</label>
            <input type="email" placeholder="you@wherever.com" value={email} onChange={e => setEmail(e.target.value)} required />
          </div>
          <button type="submit" disabled={status === 'sending' || status === 'done'}>{label}</button>
          {status === 'error' && (
            <div className="newsletter-meta" style={{ color: 'var(--accent, #c0392b)' }}>
              Couldn’t subscribe just now — please try again in a moment.
            </div>
          )}
          <div className="newsletter-meta">
            {count != null ? `${count.toLocaleString()} subscribers · ` : ''}unsub in one click
          </div>
        </form>
      </div>
    </section>
  );
}

// Hero — varies by tweak
function Hero({ heroLayout, episode }) {
  const bg = 'assets/gravel-road.jpg';
  if (heroLayout === 'split') {
    return (
      <section className="hero">
        <div className="hero-split">
          <div className="hero-text">
            <div className="eyebrow">Independent gravel · est. 2026</div>
            <h1 className="display">Gear.<br/>Grit.<br/>Gravel.</h1>
            <p style={{ fontSize: 19, color: 'var(--ink-soft)', maxWidth: '48ch' }}>
              Long rides and longer conversations. A podcast, a journal, and a community for people who care about the sport.
            </p>
            <div style={{ display: 'flex', gap: 12, marginTop: 32, flexWrap: 'wrap' }}>
              <Link to={'/podcast/' + episode.id} className="btn btn-primary">
                Listen to Episode {episode.number} <span className="arrow">→</span>
              </Link>
              <Link to="/newsletter" className="btn btn-ghost" onClick={goToSubscribe}>Subscribe <span className="arrow">→</span></Link>
            </div>
          </div>
          <div className="hero-image" style={{ backgroundImage: `url(${bg})` }} />
        </div>
      </section>
    );
  }
  if (heroLayout === 'stack') {
    return (
      <section className="hero hero-stack">
        <div className="wrap">
          <div className="eyebrow">Independent gravel cycling media · est. 2026</div>
          <h1 className="display">Gear. Grit. Gravel.</h1>
          <div style={{ display: 'grid', gridTemplateColumns: '1.1fr 1fr', gap: 48, alignItems: 'end' }}>
            <p style={{ fontSize: 22, color: 'var(--ink-soft)', maxWidth: '42ch', margin: 0 }}>
              The gravel show, and the gear behind it. Long-format interviews, honest reviews, and a community of riders who want to go long.
            </p>
            <div style={{ display: 'flex', gap: 12, justifyContent: 'flex-end', flexWrap: 'wrap' }}>
              <Link to={'/podcast/' + episode.id} className="btn btn-primary">Listen to Episode {episode.number} <span className="arrow">→</span></Link>
            </div>
          </div>
        </div>
        <div className="hero-band" style={{ backgroundImage: `url(${bg})` }} />
      </section>
    );
  }
  // overlay (default)
  return (
    <section className="hero">
      <div className="hero-overlay">
        <div className="hero-img" style={{ backgroundImage: `url(${bg})` }} />
        <div className="hero-content">
          <div className="wrap">
            <div className="eyebrow">Independent gravel cycling media · est. 2026</div>
            <h1 className="display">Gear.<br/>Grit.<br/>Gravel.</h1>
            <p className="subtle">
              Long rides and longer conversations. A podcast, a journal, and a community for people who care about the sport.
            </p>
            <div className="hero-meta">
              <Link to={'/podcast/' + episode.id} className="play-pill">
                <span className="play-icon">▶</span>
                <span>
                  <div style={{ fontSize: 10, letterSpacing: '0.14em', opacity: 0.7 }}>NOW PLAYING · EP {episode.number}</div>
                  <div style={{ marginTop: 2 }}>{episode.title}</div>
                </span>
              </Link>
              <span style={{ opacity: 0.6 }}>·</span>
              <span>{episode.duration}</span>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

function SectionHead({ eyebrow, title, meta, link, linkLabel }) {
  return (
    <div className="section-head">
      <div>
        <div className="eyebrow" style={{ marginBottom: 16 }}>{eyebrow}</div>
        <h2>{title}</h2>
      </div>
      <div className="meta">
        {link && <Link to={link}>{linkLabel || 'View all'} →</Link>}
        {!link && meta}
      </div>
    </div>
  );
}

Object.assign(window, { useRoute, Link, goToSubscribe, Topbar, Footer, NewsletterBlock, Hero, SectionHead, NAV });
