// Hawaiian Style — Shop All and the three category pages.
//
// /shop, /shop/tanning, /shop/aftersun, /shop/sunblock.
//
// These exist for search as much as for shoppers. Google builds the sitelinks
// under a result from the pages that actually exist, and until now the only
// things it could choose from were eleven articles, nine product pages and the
// homepage — so the shortcuts under our result were Sun School and FAQ rather
// than the three things we sell. [SPEC: SAP Shop All]
//
// Prices and stock come from /api/store at runtime, the same as every other
// surface. Nothing here is baked with a price: Admin can change one in a
// second and a stale number in the HTML is worse than no number, which is the
// same reasoning Product.jsx already follows for its structured data.
//
// The product NAMES and LINKS are baked, by tools/prerender.py, from the
// products/*.html files themselves. That is the half a crawler needs, it comes
// from the filesystem rather than the database, and it cannot go stale against
// pages that do not exist.

const SHOP_CATEGORIES = {
  tanning: {
    slug: 'tanning',
    name: 'Tanning',
    script: 'the soul.',
    match: p => /^Tanning/.test(p.cat || ''),
    blurb: 'Coconut oils and lotions that deepen colour while keeping skin fed. '
         + 'The oldest half of the range, and the half people come back for.',
    bg: 'radial-gradient(circle at 80% 10%, rgba(247, 223, 77, 0.45) 0%, transparent 55%), '
      + 'linear-gradient(160deg, #E78930 0%, #B85C12 100%)',
    fg: 'var(--paper)',
  },
  aftersun: {
    slug: 'aftersun',
    name: 'After Sun',
    script: 'the cool down.',
    match: p => /^After Sun/.test(p.cat || ''),
    blurb: 'Aloe and coconut, for the hours after. The half of a beach day that '
         + 'decides whether the colour stays or peels.',
    bg: 'radial-gradient(circle at 10% 90%, rgba(247, 223, 77, 0.3) 0%, transparent 55%), '
      + 'linear-gradient(160deg, #FCD5B6 0%, #F4BE92 100%)',
    fg: 'var(--brown)',
  },
  sunblock: {
    slug: 'sunblock',
    name: 'Sunblock',
    script: 'the enabler.',
    match: p => /^Sunblock/.test(p.cat || ''),
    blurb: 'SPF 15 to 50, all PABA-free and all with a PA rating — the UVA number '
         + 'most bottles on the shelf here still do not print.',
    bg: 'radial-gradient(circle at 70% 15%, rgba(247, 223, 77, 0.25) 0%, transparent 55%), '
      + 'linear-gradient(160deg, #6E83A0 0%, #465975 100%)',
    fg: 'var(--paper)',
  },
};

const SHOP_ALL = {
  slug: null,
  name: 'Shop All',
  script: 'the whole shelf.',
  match: () => true,
  blurb: 'Every bottle we make, in one place. Tanning oils and lotions, after sun, '
       + 'and sunblock from SPF 15 to 50 — made in Thailand since 1995.',
  bg: 'radial-gradient(circle at 75% 12%, rgba(247, 223, 77, 0.4) 0%, transparent 55%), '
    + 'linear-gradient(160deg, #D8721D 0%, #8E4A10 100%)',
  fg: 'var(--paper)',
};

// Breadcrumb. Nested rather than /tanning, so the trail reads
// Home > Shop > Tanning > Coconut Oil and Google can show it under the result.
const ShopCrumbs = ({ cat }) => (
  <nav className="shop-crumbs" aria-label="Breadcrumb">
    <a href="/">Home</a>
    <span aria-hidden="true">›</span>
    {cat.slug ? <a href="/shop">Shop</a> : <span>Shop</span>}
    {cat.slug && <span aria-hidden="true">›</span>}
    {cat.slug && <span>{cat.name}</span>}
  </nav>
);

const ShopHero = ({ cat, count }) => (
  <header className="shop-hero" style={{ background: cat.bg, color: cat.fg }}>
    <div className="shop-hero-in">
      <div className="shop-kicker">
        {cat.slug ? 'Category' : 'The range'}
        {count != null && <span> · {count} product{count === 1 ? '' : 's'}</span>}
      </div>
      <h1 className="shop-title">
        {cat.name}
        <span className="shop-script">{cat.script}</span>
      </h1>
      <p className="shop-blurb">{cat.blurb}</p>
    </div>
  </header>
);

// The other two categories, so a visitor who lands here from search has
// somewhere to go that is not the back button.
const ShopSwitch = ({ current }) => {
  const others = Object.values(SHOP_CATEGORIES).filter(c => c.slug !== current);
  return (
    <div className="shop-switch">
      <Eyebrow>★ Also on the shelf</Eyebrow>
      <div className="shop-switch-row">
        {current && <a href="/shop">Shop all</a>}
        {others.map(c => <a key={c.slug} href={'/shop/' + c.slug}>{c.name}</a>)}
      </div>
    </div>
  );
};

const ShopPage = ({ category = null, baked = [] }) => {
  const { useState, useEffect } = React;
  const cat = category ? SHOP_CATEGORIES[category] : SHOP_ALL;
  const [state, setState] = useState({ status: 'loading', products: [], open: false });

  useEffect(() => {
    let dead = false;
    fetch('/api/store')
      .then(r => (r.ok ? r.json() : Promise.reject(new Error(r.status))))
      .then(d => {
        if (dead) return;
        setState({
          status: 'ok',
          products: (d.products || []).filter(cat.match),
          open: !!(d.settings && d.settings.store_open),
        });
      })
      .catch(() => { if (!dead) setState({ status: 'error', products: [], open: false }); });
    return () => { dead = true; };
  }, [category]);

  // Until the API answers, show the names that were baked into the HTML rather
  // than a spinner — the page is readable from the first paint, and it is the
  // same list, only without prices.
  const showing = state.status === 'ok' ? state.products : [];
  const count = state.status === 'ok' ? showing.length : (baked.length || null);

  const addToBag = (p) => {
    try {
      const raw = localStorage.getItem('hws-cart-v1');
      const cartNow = raw ? JSON.parse(raw) : [];
      const i = cartNow.findIndex(x => x.id === p.id);
      const next = i >= 0
        ? cartNow.map((x, j) => (j === i ? { ...x, qty: (x.qty || 1) + 1 } : x))
        : [...cartNow, { id: p.id, name: p.name, cat: p.cat, price: p.price, qty: 1, img: p.img }];
      localStorage.setItem('hws-cart-v1', JSON.stringify(next));
      window.dispatchEvent(new Event('hws-cart-changed'));
    } catch (e) { /* a blocked localStorage should not break the page */ }
  };

  return (
    <>
      <TopBar />
      <Nav cartCount={0} />
      <div className="shop-wrap"><ShopCrumbs cat={cat} /></div>
      <ShopHero cat={cat} count={count} />

      <main className="shop-wrap shop-main">
        {state.status === 'error' && (
          <p className="shop-note">
            We cannot reach the shop right now. The range is still below — open a
            product for the full details, or find us at one of our{' '}
            <a href="/#where-to-buy">stockists</a>.
          </p>
        )}
        {state.status === 'ok' && !state.open && (
          <p className="shop-note">
            <strong>Online ordering opens very soon.</strong> Everything here is on
            the shelf at our <a href="/#where-to-buy">stockists</a> and in our
            marketplace shops in the meantime.
          </p>
        )}

        {state.status === 'ok' ? (
          <div className="shop-grid">
            {showing.map(p => (
              <ProductCard
                key={p.id}
                p={{ ...p, ...(window.DECORATIONS ? (window.DECORATIONS[p.id] || {}) : {}) }}
                onAdd={state.open ? addToBag : null}
              />
            ))}
          </div>
        ) : (
          // The baked list. React replaces it the moment /api/store answers.
          <ul className="shop-baked">
            {baked.map(b => (
              <li key={b.href}><a href={b.href}>{b.name}</a><span>{b.cat}</span></li>
            ))}
          </ul>
        )}

        <ShopSwitch current={cat.slug} />
      </main>

      <div style={{ height: 56 }} />
      <Footer />
    </>
  );
};

window.ShopPage = ShopPage;
window.SHOP_CATEGORIES = SHOP_CATEGORIES;
