// ReviewQuote — single pull-quote review. Used inline on SitPage (dark)
// and in the AllReviews grid on InfoPage (light).
//
// Visual: big faint open-quote glyph, italic serif body, mono caps attribution,
// five-dot rating, source link. No card chrome.

const { useRef: useReviewRef, useEffect: useReviewEffect } = React;

const ReviewQuote = ({ review, variant = 'dark' }) => {
  if (!review) return null;
  const r = review;
  const rating = Math.max(0, Math.min(5, r.rating || 0));
  return (
    <figure className={`review review--${variant}`}>
      <span className="review__glyph" aria-hidden>&#8220;</span>
      <blockquote className="review__body">
        {r.quote}
      </blockquote>
      <figcaption className="review__attrib">
        <span className="review__who">
          {r.reviewer_first}
          {r.reviewer_city ? `, ${r.reviewer_city}` : ''}
        </span>
        {r.stay_start && (
          <span className="review__when">
            {new Date(r.stay_start + 'T00:00:00').toLocaleString('en', { month: 'short', year: 'numeric' }).toLowerCase()}
          </span>
        )}
        <span className="review__dots" aria-label={`${rating} out of 5`}>
          {Array.from({ length: 5 }).map((_, i) => (
            <span key={i} className={i < rating ? 'is-on' : ''} />
          ))}
        </span>
        <span className="review__source">
          via trustedhousesitters
        </span>
      </figcaption>
    </figure>
  );
};

// AllReviews — every verified review from TrustedHousesitters. Shown on
// the Info page. Two-column masonry on desktop, one-column on mobile.
// No featured/non-featured split — every review is equal weight.
const AllReviews = () => {
  const list = window.REVIEWS || [];
  const gridRef = useReviewRef(null);
  const headRef = useReviewRef(null);

  // Reveal each review as it enters the viewport. 39 reviews arriving in
  // quick succession reinforce the count without a loading-screen feel —
  // each fade carries a "and another" weight for the trust job. The
  // header block fades in on the same observer for grammar consistency
  // (see docs/adr/0001-info-page-motion-grammar.md).
  // Observer unobserves on first intersection so reveal is a one-shot.
  useReviewEffect(() => {
    const grid = gridRef.current;
    if (!grid) return;
    const figs = grid.querySelectorAll('.review');
    const head = headRef.current;
    const mqReduced = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)');
    if (mqReduced && mqReduced.matches) {
      figs.forEach(f => f.classList.add('is-in'));
      if (head) head.classList.add('is-in');
      return;
    }
    const io = new IntersectionObserver((entries) => {
      for (const e of entries) {
        if (e.isIntersecting) {
          e.target.classList.add('is-in');
          io.unobserve(e.target);
        }
      }
    }, { threshold: 0.12, rootMargin: '0px 0px -8% 0px' });
    figs.forEach(f => io.observe(f));
    if (head) io.observe(head);
    return () => io.disconnect();
  }, [list.length]);

  if (!list.length) return null;
  return (
    <section className="all-reviews">
      <header ref={headRef} className="all-reviews__head">
        <div>
          <h2 className="all-reviews__title">
            {window.REVIEW_STATS?.count || list.length} verified reviews
          </h2>
        </div>
        <div className="all-reviews__meta">
          <span className="mono-label">
            avg {window.REVIEW_STATS?.average?.toFixed(2) || '5.00'}/5
            {' · '}
            {window.REVIEW_STATS?.five_star || list.length} five-star
          </span>
          <a
            href="https://www.trustedhousesitters.com/house-and-pet-sitters/united-states/colorado/boulder/l/2277339/"
            target="_blank" rel="noopener noreferrer"
            className="link mono-label"
          >
            see on trustedhousesitters →
          </a>
        </div>
      </header>
      <div ref={gridRef} className="all-reviews__grid">
        {list.map(r => (
          <ReviewQuote key={r.id} review={r} variant="light" />
        ))}
      </div>
    </section>
  );
};

window.ReviewQuote = ReviewQuote;
window.AllReviews = AllReviews;
