// primitives.jsx — Responsive Hauling shared primitives.
// Logo, icon set, Btn, SectionHeading, IconChip, path helpers, data access.
// Loads before sections.jsx / pages.jsx / app.jsx. Exposes globals via window.

const { useState: usePState, useEffect: usePEffect, useRef: usePRef } = React;

/* ───────── Depth-aware path helpers ─────────
   Wrapper contract: home lives at ./ , every other route (category, item,
   about, contact, ...) lives exactly one level deep at ./<slug>/. That's the
   only nesting depth generate-wrappers.mjs produces, so href()/imgSrc() only
   need to know whether the current page IS the home page or not. */
const PAGE_CFG = (typeof window !== 'undefined' && window.__PAGE_CONFIG__) || { type: 'home', slug: '' };
const IS_HOME = !PAGE_CFG.slug || PAGE_CFG.slug === '';
const DEPTH_PREFIX = IS_HOME ? './' : '../';

function href(slug) {
  const clean = (slug || '').replace(/^\/+|\/+$/g, '');
  if (!clean) return DEPTH_PREFIX;
  return DEPTH_PREFIX + clean + '/';
}
function imgSrc(filename) {
  return DEPTH_PREFIX + 'assets/img/' + filename;
}

/* ───────── Business data access (graceful fallbacks) ───────── */
const FALLBACK_DATA = {
  phone: '(510) 244-0285',
  phoneHref: 'tel:+15102440285',
  email: 'ricardo@responsivehauling.com',
  cities: ['Hayward', 'Oakland', 'Berkeley', 'San Leandro', 'San Francisco', 'San Mateo', 'Palo Alto', 'Fremont', 'San Ramon', 'Livermore', 'Pleasanton', 'Danville'],
  categories: [],
  items: {},
  tagline: 'Haul it all with one call!'
};
function getRHData() {
  const d = (typeof window !== 'undefined' && window.RH_DATA) || {};
  return {
    phone: d.phone || FALLBACK_DATA.phone,
    phoneHref: d.phoneHref || FALLBACK_DATA.phoneHref,
    email: d.email || FALLBACK_DATA.email,
    cities: (d.cities && d.cities.length) ? d.cities : FALLBACK_DATA.cities,
    categories: d.categories || FALLBACK_DATA.categories,
    items: d.items || FALLBACK_DATA.items,
    // v2: getRHData is a WHITELIST, not a passthrough — a key missing from this
    // object is invisible to every component. `booking` has to be listed here or
    // BookBtn/BookingEmbed silently render nothing.
    booking: d.booking || null,
    tagline: d.tagline || FALLBACK_DATA.tagline
  };
}
function getCategory(slug) {
  const data = getRHData();
  return data.categories.find((c) => c.slug === slug) || null;
}
function getItem(slug) {
  const data = getRHData();
  return data.items[slug] || null;
}
function getCityPage(slug) {
  const d = (typeof window !== 'undefined' && window.RH_DATA) || {};
  return (d.cityPages && d.cityPages[slug]) || null;
}
function getPost(slug) {
  const d = (typeof window !== 'undefined' && window.RH_DATA) || {};
  return (d.posts && d.posts[slug]) || null;
}
/* City name -> city page slug (e.g. "San Leandro" -> "san-leandro-ca"), only if a page exists */
function citySlug(cityName) {
  return cityName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '') + '-ca';
}

/* ───────── Balanced grid column picker ─────────
   Avoids a trailing row with a single orphan card. Prefers 3 columns, then
   4, then 2 — only accepting a candidate if n <= candidate (single row) or
   n % candidate !== 1 (no lonely last row). */
function pickGridCols(n) {
  if (!n || n <= 0) return 3;
  for (const c of [3, 4, 2]) {
    if (n <= c || n % c !== 1) return c;
  }
  return 2;
}

/* ───────── Logo ───────── */
function Logo({ size = 'md', dark = false }) {
  const cls = `logo logo-${size}`.trim();
  return (
    <a href={href('')} className={cls} aria-label="Responsive Hauling — home">
      <img className="logo-img" src={imgSrc('Business-logo-2-1920w.png')} alt="Responsive Hauling" />
    </a>
  );
}
function RecycleMark({ size = 28 }) {
  return (
    <img
      className="recycle-mark"
      style={{ height: size }}
      src={imgSrc('Recycle-Icon-2-1920w.png')}
      alt=""
      aria-hidden="true"
      loading="lazy"
    />
  );
}

/* ───────── Icon set (inline SVG, stroke-based, currentColor) ───────── */
function svgWrap(children, size, viewBox = '0 0 24 24') {
  return (
    <svg width={size} height={size} viewBox={viewBox} fill="none" xmlns="http://www.w3.org/2000/svg">
      {children}
    </svg>
  );
}
function IconPhone({ size = 16 }) {
  return svgWrap(<path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92z" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" fill="none"/>, size);
}
function IconTruck({ size = 20 }) {
  return svgWrap(<>
    <path d="M1 3h13v13H1z" stroke="currentColor" strokeWidth="1.8" strokeLinejoin="round"/>
    <path d="M14 8h4l4 4v4h-8V8z" stroke="currentColor" strokeWidth="1.8" strokeLinejoin="round"/>
    <circle cx="5.5" cy="18" r="2" stroke="currentColor" strokeWidth="1.8"/>
    <circle cx="17.5" cy="18" r="2" stroke="currentColor" strokeWidth="1.8"/>
  </>, size);
}
function IconClock({ size = 20 }) {
  return svgWrap(<>
    <circle cx="12" cy="12" r="9.5" stroke="currentColor" strokeWidth="1.8"/>
    <path d="M12 7v5l3.2 2" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
  </>, size);
}
function IconShield({ size = 20 }) {
  return svgWrap(<>
    <path d="M12 2.5 4 5.5v6c0 5 3.4 8.4 8 10 4.6-1.6 8-5 8-10v-6L12 2.5z" stroke="currentColor" strokeWidth="1.8" strokeLinejoin="round"/>
    <path d="M8.5 12.2l2.4 2.4 4.6-5" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
  </>, size);
}
function IconBroom({ size = 20 }) {
  return svgWrap(<>
    <path d="M14 3l6 6-2.5 2.5" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
    <path d="M12.5 4.5l-9 9 2.2 5.8 5.8 2.2 9-9-8-8z" stroke="currentColor" strokeWidth="1.8" strokeLinejoin="round"/>
    <path d="M3.5 20.5l4-4" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round"/>
  </>, size);
}
function IconLeaf({ size = 20 }) {
  return svgWrap(<>
    <path d="M20 4C10 4 4 10 4 18c0 .55.45 2 2 2 8 0 14-6 14-16 0-.2 0-.2 0 0z" stroke="currentColor" strokeWidth="1.8" strokeLinejoin="round"/>
    <path d="M6 18c3-3 7-7 12-12" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round"/>
  </>, size);
}
function IconArrow({ size = 14 }) {
  return svgWrap(<>
    <line x1="5" y1="12" x2="19" y2="12" stroke="currentColor" strokeWidth="2.3" strokeLinecap="round" className="icon-arrow"/>
    <polyline points="13 5 20 12 13 19" stroke="currentColor" strokeWidth="2.3" strokeLinecap="round" strokeLinejoin="round" className="icon-arrow"/>
  </>, size);
}
function IconStar({ size = 16 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor">
      <polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/>
    </svg>
  );
}
function IconCheck({ size = 14 }) {
  return svgWrap(<polyline points="20 6 9 17 4 12" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"/>, size);
}
function IconCaret({ size = 12, className = '' }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" className={className}>
      <polyline points="6 9 12 15 18 9" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" className="caret"/>
    </svg>
  );
}
function IconMail({ size = 16 }) {
  return svgWrap(<>
    <rect x="2.5" y="5" width="19" height="14" rx="2" stroke="currentColor" strokeWidth="1.8"/>
    <path d="M3.5 6.5l8.5 6 8.5-6" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
  </>, size);
}
function IconPin({ size = 16 }) {
  return svgWrap(<>
    <path d="M12 21s7-6.5 7-12a7 7 0 1 0-14 0c0 5.5 7 12 7 12z" stroke="currentColor" strokeWidth="1.8" strokeLinejoin="round"/>
    <circle cx="12" cy="9" r="2.4" stroke="currentColor" strokeWidth="1.8"/>
  </>, size);
}

/* Category icons: home / briefcase / curb / broom / plug / sofa / heart / box */
function IconHome({ size = 22 }) {
  return svgWrap(<>
    <path d="M3.5 11L12 4l8.5 7" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
    <path d="M5.5 9.5V20h13V9.5" stroke="currentColor" strokeWidth="1.8" strokeLinejoin="round"/>
    <path d="M9.5 20v-6h5v6" stroke="currentColor" strokeWidth="1.8" strokeLinejoin="round"/>
  </>, size);
}
function IconBriefcase({ size = 22 }) {
  return svgWrap(<>
    <rect x="2.5" y="7.5" width="19" height="12" rx="2" stroke="currentColor" strokeWidth="1.8"/>
    <path d="M8 7.5V5.5a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" stroke="currentColor" strokeWidth="1.8" strokeLinejoin="round"/>
    <path d="M2.5 13h19" stroke="currentColor" strokeWidth="1.8"/>
  </>, size);
}
function IconCurb({ size = 22 }) {
  return svgWrap(<>
    <path d="M3 18h18" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round"/>
    <path d="M6 18v-4.5l3-3h6l3 3V18" stroke="currentColor" strokeWidth="1.8" strokeLinejoin="round"/>
    <path d="M6 18l-2.5 3M18 18l2.5 3" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round"/>
  </>, size);
}
function IconPlug({ size = 22 }) {
  return svgWrap(<>
    <path d="M9 2v6M15 2v6" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round"/>
    <path d="M6 8h12v4a6 6 0 0 1-12 0V8z" stroke="currentColor" strokeWidth="1.8" strokeLinejoin="round"/>
    <path d="M12 18v4" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round"/>
  </>, size);
}
function IconSofa({ size = 22 }) {
  return svgWrap(<>
    <path d="M4 11V8a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v3" stroke="currentColor" strokeWidth="1.8" strokeLinejoin="round"/>
    <rect x="2.5" y="11" width="19" height="6" rx="2" stroke="currentColor" strokeWidth="1.8"/>
    <path d="M3.5 17v3M20.5 17v3" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round"/>
  </>, size);
}
function IconHeart({ size = 22 }) {
  return svgWrap(<path d="M12 20s-7.5-4.8-9.7-9.6C.7 7 2.4 3.5 6 3c2.2-.3 4.2.9 6 3 1.8-2.1 3.8-3.3 6-3 3.6.5 5.3 4 3.7 7.4C19.5 15.2 12 20 12 20z" stroke="currentColor" strokeWidth="1.8" strokeLinejoin="round"/>, size);
}
function IconBox({ size = 22 }) {
  return svgWrap(<>
    <path d="M3 8l9-4.5L21 8l-9 4.5L3 8z" stroke="currentColor" strokeWidth="1.8" strokeLinejoin="round"/>
    <path d="M3 8v9l9 4.5V12.5M21 8v9l-9 4.5" stroke="currentColor" strokeWidth="1.8" strokeLinejoin="round"/>
  </>, size);
}

const CATEGORY_ICONS = {
  home: IconHome,
  briefcase: IconBriefcase,
  curb: IconCurb,
  broom: IconBroom,
  plug: IconPlug,
  sofa: IconSofa,
  heart: IconHeart,
  box: IconBox
};
function CategoryIcon({ name, size = 22 }) {
  const Cmp = CATEGORY_ICONS[name] || IconBox;
  return <Cmp size={size} />;
}

function Stars({ n = 5, size = 14 }) {
  return (
    <span className="rb-stars" aria-label={`${n} out of 5 stars`}>
      {Array.from({ length: n }).map((_, i) => <IconStar key={i} size={size} />)}
    </span>
  );
}

/* ───────── Btn ───────── */
function Btn({ href: hrefProp, tel, variant = 'primary', size, icon, arrow = true, children, ...rest }) {
  const cls = `btn btn-${variant}${size ? ' btn-' + size : ''}`;
  const finalHref = tel ? `tel:${tel}` : hrefProp;
  return (
    <a className={cls} href={finalHref} {...rest}>
      {icon}
      <span>{children}</span>
      {arrow && <IconArrow size={13} />}
    </a>
  );
}

/* ───────── SectionHeading ───────── */
function SectionHeading({ eyebrow, title, sub, dark = false, align = 'split' }) {
  if (align === 'center') {
    return (
      <div className="section-head" style={{ gridTemplateColumns: '1fr', textAlign: 'center', justifyItems: 'center' }}>
        <div>
          {eyebrow && <div className={`eyebrow${dark ? ' on-dark' : ''}`}>{eyebrow}</div>}
          <h2 className="h-display h2" style={{ marginTop: 12, color: dark ? '#fff' : undefined }}>{title}</h2>
        </div>
        {sub && <p className="lede" style={{ margin: '0 auto', color: dark ? 'rgba(255,255,255,.85)' : undefined }}>{sub}</p>}
      </div>
    );
  }
  return (
    <div className="section-head">
      <div>
        {eyebrow && <div className={`eyebrow${dark ? ' on-dark' : ''}`}>{eyebrow}</div>}
        <h2 className="h-display h2" style={{ marginTop: 12, color: dark ? '#fff' : undefined }}>{title}</h2>
      </div>
      {sub && <p className="lede" style={{ color: dark ? 'rgba(255,255,255,.85)' : undefined }}>{sub}</p>}
    </div>
  );
}

/* ───────── IconChip ───────── */
function IconChip({ children, tone = 'green', size = 'md' }) {
  const cls = `icon-chip${tone === 'blue' ? ' blue' : tone === 'dark' ? ' on-dark' : ''}${size === 'sm' ? ' sm' : size === 'lg' ? ' lg' : ''}`;
  return <span className={cls}>{children}</span>;
}

/* ───────── Fixed business constants (not part of RH_DATA contract) ───────── */
const USPS = [
  { icon: IconClock, title: 'On Time Crew', blurb: '2-hour arrival windows — we show up when we say we will, every time.' },
  { icon: IconTruck, title: '19-Yard Trucks', blurb: '16ft / 8ft / 4ft trucks that hold more per load than the competition.' },
  { icon: IconShield, title: 'Fully Licensed & Insured', blurb: 'Every job, every crew member — covered and accountable.' },
  { icon: IconBroom, title: 'Broom Sweep Clean', blurb: 'We always sweep up after the job. You never lift a finger.' }
];

const HOW_STEPS = [
  { num: '01', title: 'Call or Book', blurb: 'Call (510) 244-0285 or book online for a free, no-obligation estimate.' },
  { num: '02', title: 'We Show Up', blurb: 'Our crew shows up in your 2-hour window, uniformed, ready, and fully insured.' },
  { num: '03', title: "Everything's Gone", blurb: 'We haul it all — recycling and donating first, then a broom-clean sweep of the space.' },
  { num: '04', title: "Pay When It's Done", blurb: 'Volume-based, all-inclusive pricing. Pay by card, cash, or check — financing available.' }
];

const TEAM = [
  { name: 'Ricardo', role: 'Owner · 8+ yrs', bio: 'ATV riding and mountain biking on days off.', photo: null },
  { name: 'Enrique', role: '4+ yrs', bio: 'Star Wars fan and Japanese antiques collector.', photo: 'Enrique-1920w.png' },
  { name: 'Brandon', role: '2+ yrs', bio: 'Video games, hunting, fishing, and anime.', photo: null },
  { name: 'Carlos', role: '6+ yrs', bio: 'Spends his free time with family.', photo: null }
];

const SOCIAL_LINKS = {
  facebook: 'https://facebook.com/responsivehauling',
  instagram: 'https://instagram.com/responsive_hauling',
  yelp: 'https://www.yelp.com/biz/responsive-hauling-hayward-10',
  google: 'https://maps.app.goo.gl/Fv427meek2rN2JQA7'
};

/* Real Yelp reviews — pulled from Yelp Fusion on 2026-08-25.
   Business jCK62XYM16UqhThEFOgnmA · rating 5.0 · review_count 262.
   Fusion caps this endpoint at THREE reviews and truncates the text itself,
   which is why the excerpts end mid-sentence. Nothing here is paraphrased.
   ⚠️ Never hand-write an entry into this array. If more reviews are wanted,
   pull them from AgencyAnalytics. Pa L.'s 5-star review was PULLED 2026-08-25: Fusion's truncation cut it mid-complaint; restore only with the full text from AA. Also: pull them from AgencyAnalytics (Yelp Reviews source is connected for this
   client, AA id 1813564) — not from memory. */
/* Real Google reviews — read off the rendered Google Maps listing
   (maps.app.goo.gl/Fv427meek2rN2JQA7, CID 0x2a01e441eb191b02) on 2026-08-25.
   Listing showed rating 5.0, 322 reviews. The embedded view exposes only
   three review cards; these are verbatim. The Places API does NOT index this
   business (searchText/findplace/nearby all ZERO_RESULTS on 2026-08-25), so
   these cannot be refreshed programmatically — re-read the listing.
   ⚠️ Never hand-write entries. Dates on the listing were relative
   ("8 months ago"); we store the source label only. */
const GOOGLE_STATS = { rating: 5.0, count: 322, checked: '2026-08-25' };
const GOOGLE_REVIEWS = [
  {
    name: 'Mohan C',
    rating: 5,
    text: 'Ricardo and team are, hands down, the best! I was helping my family move across the state and our house had about 30 years worth of stuff that needed to be hauled away. Ricardo was extremely professional and his team works really quickly.'
  },
  {
    name: 'Christopher Taylor',
    rating: 5,
    text: 'Enrique and his crew were fabulous! Working together with him, we got what might have been a six hour job done in 3 1/2 hours. I could not be more pleased. Regards, Christopher.'
  },
  {
    name: 'Peter Tuttle',
    rating: 5,
    text: 'The crew showed up in scheduled window. Polite and professional men. Quickly gathered all items we were disposing and made quick work of able to pay with debit card without issue. Very nice experience, have used them several times before and cannot recommend them enough to others.'
  }
];

const YELP_STATS = { rating: 5.0, count: 262, checked: '2026-08-25' };
const YELP_REVIEWS = [
  {
    name: 'Lisa S.',
    date: '2026-08-05',
    rating: 5,
    text: 'Amazing service! I was able to get a quote and pickup in the same day. Communication was great and the associates that handled the pickup were very friendly...'
  },
  {
    name: 'Curt',
    date: '2026-08-24',
    rating: 5,
    text: 'I had a last minute need and the Responsive Hauling guys were quick to respond and got a truck to me within about an hour. I appreciated the back and forth...'
  }
];

/* Projected from real lat/lon (computed 2026-08-25); viewBox 800x520. */
const CITY_MAP_PINS = [
  { name: "Berkeley", x: 86, y: 70 },
  { name: "Emeryville", x: 70, y: 115 },
  { name: "Oakland", x: 88, y: 145 },
  { name: "Alameda", x: 126, y: 188 },
  { name: "San Leandro", x: 235, y: 233 },
  { name: "Dublin", x: 516, y: 258 },
  { name: "Castro Valley", x: 324, y: 267 },
  { name: "Livermore", x: 730, y: 281 },
  { name: "San Lorenzo", x: 273, y: 282 },
  { name: "Hayward", x: 331, y: 295 },
  { name: "Pleasanton", x: 594, y: 302 },
  { name: "Union City", x: 378, y: 379 },
  { name: "Fremont", x: 448, y: 429 },
  { name: "Newark", x: 383, y: 450 }
];

const BEFORE_AFTER_PAIRS = [
  { before: 'Before1-1920w.jpg', after: 'After1-1920w.jpg', label: 'Garage cleanout' },
  { before: 'Before2-1920w.jpg', after: 'After2-1920w.jpg', label: 'Property cleanout' },
  { before: 'Before3-1920w.jpg', after: 'After3-1920w.jpg', label: 'Curbside pickup' }
];

// Expose to window for sections.jsx / pages.jsx / app.jsx
Object.assign(window, {
  href, imgSrc, getRHData, getCategory, getItem, getCityPage, getPost, citySlug, pickGridCols,
  Logo, RecycleMark,
  IconPhone, IconTruck, IconClock, IconShield, IconBroom, IconLeaf, IconArrow,
  IconStar, IconCheck, IconCaret, IconMail, IconPin, CategoryIcon, Stars,
  Btn, SectionHeading, IconChip,
  USPS, HOW_STEPS, TEAM, SOCIAL_LINKS, BEFORE_AFTER_PAIRS, YELP_REVIEWS, YELP_STATS, CITY_MAP_PINS, GOOGLE_REVIEWS, GOOGLE_STATS
});
