/* Aevitan website — Portfolio: filterable catalog with public "from" pricing (0043). */
const DSp = window.AevitanDesignSystem_6a042d;

// Same derivation Chrome.jsx uses — local const, no cross-script lexical coupling.
const PORTFOLIO_PORTAL_URL = (typeof location !== 'undefined' && location.hostname === 'localhost')
  ? 'http://localhost:3001'
  : 'https://portal.aevitan.com';
// B39 (a11y): the "Join now!" inline CTA gets a real root-relative href for keyboard focus + link
// semantics; onClick still drives SPA nav. Uniquely named — Babel scripts share one lexical scope.
const RP_PORT = (window.AEV_ROUTES || {}).paths || {};

// Built-in fallback (offline / API unavailable) — normalized to the SAME object shape as the live
// mapping (id:null → the notify button stays inert), so there is exactly one render path.
const CATALOG = [
  ['AEVI APEX-T', 'Tirzepatide · 60 mg', 'Metabolic', 'available'],
  ['AEVI APEX-R', 'Retatrutide · 50 mg', 'Metabolic', 'available'],
  ['AEVIRA LUMA', 'GLOW Blend · 70 mg', 'Recovery', 'available'],
  ['AEVIRA G-100', 'GHK-Cu · 100 mg', 'Wellness', 'available'],
  ['Semaglutide', 'GLP-1 · 10 mg', 'Metabolic', 'review'],
  ['BPC-157 / TB-500', 'Recovery blend', 'Recovery', 'review'],
  ['NAD+', '1000 mg', 'Longevity', 'review'],
  ['Epithalon', '40 mg', 'Longevity', 'review'],
  ['Cagrilintide', '10 mg', 'Metabolic', 'review'],
  ['MOTS-C', '10 mg', 'Longevity', 'review'],
  ['SS-31', '10 mg', 'Longevity', 'review'],
  ['Thymosin Alpha-1', '10 mg', 'Wellness', 'review'],
].map(([name, sub, cat, status]) => ({
  id: null, name, sub, cat, status, image: null, imageFull: null, priceUsd: null, floorUsd: null, presentation: null,
}));
const FILTERS = ['All', 'Metabolic', 'Recovery', 'Longevity', 'Wellness'];

// B54: a RANGE, not a "from". Aevitan does not sell — the consultant sets the final price within
// the product's floor and retail bounds, so a single figure would imply a price we do not honour.
function priceLabel(p) {
  const money = (n) => `$${n.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
  if (p.floorUsd != null && p.priceUsd != null && p.priceUsd > p.floorUsd) {
    return `Price range: ${money(p.floorUsd)} \u2013 ${money(p.priceUsd)}`;
  }
  const single = p.floorUsd != null ? p.floorUsd : p.priceUsd;
  return single != null ? `Price range: ${money(single)}` : null;
}

function Portfolio({ go }) {
  const { Kicker, ProductCard, Button, Badge, Monogram } = DSp;
  const [filter, setFilter] = React.useState('All');
  // batch 9: click a card -> spotlight modal for that product (Esc/backdrop/× close).
  const [detail, setDetail] = React.useState(null);
  React.useEffect(() => {
    if (!detail) return undefined;
    const onKey = (e) => { if (e.key === 'Escape') setDetail(null); };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [detail]);
  // B49: the homepage "The collection" More+ deep-links here with a product id in a window-scoped
  // signal. Capture it once on mount (clearing the global so later visits don't reopen it), then
  // open its modal as soon as the live catalog carrying that id has loaded.
  const pendingProduct = React.useRef(
    typeof window !== 'undefined' ? window.AEV_OPEN_PRODUCT || null : null,
  );
  React.useEffect(() => { if (typeof window !== 'undefined') window.AEV_OPEN_PRODUCT = null; }, []);
  // Live catalog from the Aevitan platform (anon-only products_public). Starts as null (loading) so
  // the built-in list NEVER flashes before the real catalog paints — the fallback is used ONLY when
  // the API is empty/unavailable (offline), so the page still degrades gracefully without a network.
  const [catalog, setCatalog] = React.useState(null);
  React.useEffect(() => {
    let alive = true;
    fetch('/api/products')
      .then((r) => r.json())
      .then((d) => {
        if (!alive) return;
        if (d && Array.isArray(d.products) && d.products.length) {
          setCatalog(d.products.map((p) => ({
            id: p.id,
            name: p.name,
            sub: p.presentation || p.subcategory || p.category || '',
            // B34: never launder an uncategorized product into a real category.
            cat: p.category || 'Uncategorized',
            status: p.status === 'available' ? 'available' : 'review',
            image: p.image || null,
            imageFull: p.imageFull || p.image || null,
            priceUsd: p.priceUsd ?? null,
            floorUsd: p.floorUsd ?? null,
            presentation: p.presentation || null,
            actives: Array.isArray(p.actives) ? p.actives : [],
            // B54.2: "Tirzepatide 29 mg" — the medicine-first headline; brand moves to the small line
            activesLabel: p.activesLabel || null,
          })));
        } else {
          setCatalog(CATALOG); // empty API response → offline fallback
        }
      })
      .catch(() => { if (alive) setCatalog(CATALOG); }); // network error → offline fallback
    return () => { alive = false; };
  }, []);
  // B49: once the live catalog holds the deep-linked product, open its spotlight modal.
  React.useEffect(() => {
    if (!pendingProduct.current || !catalog) return;
    const hit = catalog.find((p) => p.id === pendingProduct.current);
    if (hit) { setDetail(hit); pendingProduct.current = null; }
  }, [catalog]);
  // B33 (owner): both product CTAs land on the portal sign-in — interest and notify are
  // member actions, so the door is the login (new visitors reach Join via the line above the grid).
  const goLogin = () => { window.location.href = PORTFOLIO_PORTAL_URL + '/login'; };
  const actions = (p, big) => (
    p.status === 'available'
      ? <Button variant="gold" size={big ? 'md' : 'sm'} onClick={(e) => { e.stopPropagation(); goLogin(); }}>I'm interested!</Button>
      : <Button variant="ghost" size={big ? 'md' : 'sm'} onClick={(e) => { e.stopPropagation(); goLogin(); }}>Notify me</Button>
  );
  const shown = (catalog || []).filter(p => filter === 'All' || p.cat === filter);
  // The Uncategorized chip appears only when such products exist (B34 — no permanent empty filter).
  const filters = FILTERS.concat((catalog || []).some((p) => p.cat === 'Uncategorized') ? ['Uncategorized'] : []);
  return (
    <section className="aevsite-band aevsite-band--top">
      <div className="aevsite-wrap aevsite-reveal">
        <Kicker>Portfolio</Kicker>
        <h2 className="aevsite-h2">The full catalog, including what's still in review.</h2>
        <p className="muted">Products are requested through the independent consultant assigned to you as a Longevity Club member.{' '}
          <a className="aevsite-inline" href={RP_PORT.account} onClick={(e) => { e.preventDefault(); go('account'); }}>Join now!</a>
        </p>
        {/* B54: the renders are Aevitan artwork, not photographs of the shipped unit. */}
        <p className="muted sm">Images are for illustrative purposes only.</p>
        <div className="aevsite-filters">
          {filters.map(f => (
            <span key={f} className={`aevsite-flt ${filter === f ? 'on' : ''}`} onClick={() => setFilter(f)}>{f}</span>
          ))}
        </div>
        <div className="aevsite-grid4">
          {shown.map((p) => (
            <ProductCard
              key={p.id || p.name}
              name={p.activesLabel || p.name}
              category={p.activesLabel ? p.name : p.cat}
              subtitle={p.sub}
              status={p.status}
              image={p.image || undefined}
              onClick={() => setDetail(p)}
              footer={
                <React.Fragment>
                  {priceLabel(p) ? <span className="aev-pcard__price">{priceLabel(p)}</span> : null}
                  {actions(p, false)}
                </React.Fragment>
              }
            />
          ))}
        </div>
      </div>
      {detail ? (
        <div className="aevsite-pdetail" onMouseDown={(e) => { if (e.target === e.currentTarget) setDetail(null); }}>
          <div className="aevsite-pdetail__panel">
            <button type="button" className="aevsite-pdetail__x" aria-label="Close" onClick={() => setDetail(null)}>×</button>
            <div className="aevsite-pdetail__img">
              {detail.image
                ? <img src={detail.imageFull || detail.image} alt={detail.name} />
                : <Monogram size={54} tone="outline" />}
            </div>
            <div className="aevsite-pdetail__body">
              <span className="aevsite-pdetail__cat">{detail.activesLabel ? detail.name : detail.cat}</span>
              <h3 className="aevsite-pdetail__name">{detail.activesLabel || detail.name}</h3>
              {detail.presentation || detail.sub
                ? <p className="aevsite-pdetail__pres">{detail.presentation || detail.sub}</p>
                : null}
              <Badge variant={detail.status === 'available' ? 'available' : 'review'} />
              {priceLabel(detail) ? <div className="aevsite-pdetail__price">{priceLabel(detail)}</div> : null}
              <div className="aevsite-pdetail__foot">{actions(detail, true)}</div>
            </div>
          </div>
        </div>
      ) : null}
    </section>
  );
}

window.Portfolio = Portfolio;
