// ====================================================================
// HQ REVIEW ANALYSIS, brand-wide Google Business Profile review summary.
// A corporate-level read on what customers are saying about FreshNest
// across all 700 Google Business Profiles: rating + volume trends,
// sentiment, the themes driving praise and complaints, representative
// quotes, and the locations pulling the brand average up or down.
// Aggregates the live 700-location portfolio so headline numbers
// reconcile with the Locations tab and the per-location detail pages.
// ====================================================================
(function () {
const { useState, useMemo } = React;
const T = (...a) => (window.toast || (() => {}))(...a);

const TONES = {
  ok:   { bg: 'var(--sage-soft)',     col: 'var(--sage)' },
  warn: { bg: 'var(--marigold-soft)', col: '#917200' },
  bad:  { bg: 'var(--terra-soft)',    col: '#a12118' },
  info: { bg: 'var(--sky-soft)',      col: 'var(--sky)' },
  neutral: { bg: 'var(--cream)',      col: 'var(--ink-3)' },
};
function Pill({ tone = 'neutral', children, dot }) {
  const t = TONES[tone] || TONES.neutral;
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5, padding: '3px 9px', fontSize: 11, fontWeight: 700, borderRadius: 999, background: t.bg, color: t.col, whiteSpace: 'nowrap' }}>
      {dot && <span style={{ width: 6, height: 6, borderRadius: '50%', background: t.col }}/>}
      {children}
    </span>
  );
}
const Stars = ({ n, size = 13 }) => (
  <span style={{ color: 'var(--marigold)', fontSize: size, letterSpacing: 0.5, whiteSpace: 'nowrap' }}>
    {'★'.repeat(n)}<span style={{ color: 'var(--cream-3)' }}>{'★'.repeat(5 - n)}</span>
  </span>
);
const Label = ({ children, hint }) => (
  <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', margin: '24px 0 12px' }}>
    <div style={{ fontSize: 11, fontWeight: 700, letterSpacing: '.08em', textTransform: 'uppercase', color: 'var(--ink-3)' }}>{children}</div>
    {hint && <span style={{ fontSize: 11, color: 'var(--ink-4)' }}>{hint}</span>}
  </div>
);
const fmt = (x) => x >= 1000 ? (x / 1000).toFixed(x >= 10000 ? 0 : 1) + 'k' : '' + Math.round(x);

function HqReviewAnalysis({ data, portfolio = [], onOpen = () => {} }) {
  const A = useMemo(() => {
    const locs = portfolio.length ? portfolio : [];
    const n = locs.length || 1;
    const totalReviews = locs.reduce((a, l) => a + (l.reviewsCount || l.reviews || 0), 0) || 0;
    // Brand rating is anchored to the network source of truth (4.6★); the sample
    // portfolio only supplies review volume + distribution shape.
    const sotRating = data && data.network && data.network.performance ? data.network.performance.avgRating : null;
    const wRating = sotRating != null ? sotRating : (totalReviews
      ? locs.reduce((a, l) => a + (l.rating || 0) * (l.reviewsCount || l.reviews || 0), 0) / totalReviews
      : 0);

    // Star distribution, anchored to the brand average, brand-realistic skew.
    const fiveShare = Math.min(0.74, Math.max(0.42, (wRating - 2.6) / 2.4));
    const dist = {
      5: fiveShare,
      4: 0.22 - (fiveShare - 0.6) * 0.2,
      3: 0.09,
      2: 0.05,
      1: 1 - fiveShare - (0.22 - (fiveShare - 0.6) * 0.2) - 0.09 - 0.05,
    };
    const distCount = Object.fromEntries(Object.entries(dist).map(([k, v]) => [k, Math.max(0, Math.round(v * totalReviews))]));

    const positive = Math.round((dist[5] + dist[4]) * 100);
    const neutral  = Math.round(dist[3] * 100);
    const negative = 100 - positive - neutral;

    // 12-month review volume + rating trend (deterministic, seasonal).
    const months = ['Jul','Aug','Sep','Oct','Nov','Dec','Jan','Feb','Mar','Apr','May','Jun'];
    const baseMonthly = Math.round(totalReviews * 0.052);
    const trend = months.map((m, i) => {
      const seasonal = 1 + 0.18 * Math.sin((i / 12) * Math.PI * 2) + (i / 11) * 0.22;
      return {
        m,
        vol: Math.round(baseMonthly * seasonal),
        rating: Math.round((wRating - 0.25 + (i / 11) * 0.28) * 100) / 100,
      };
    });
    const thisMonth = trend[trend.length - 1].vol;
    const lastMonth = trend[trend.length - 2].vol;
    const volDelta = Math.round((thisMonth - lastMonth) / lastMonth * 100);

    // Themes, brand-scale, home-services-coherent. Counts proportional to footprint.
    const positiveThemes = [
      { theme: 'Cleaning quality & thoroughness', share: 31, locs: 671, delta: +6, quote: 'They cleaned spots we never even think about, the baseboards are unreal.', city: 'Chicago Loop' },
      { theme: 'Friendly, attentive staff', share: 26, locs: 654, delta: +4, quote: 'Marcus at the counter remembered my refill order from last week. That kind of service is rare.', city: 'Austin Downtown' },
      { theme: 'Product value',             share: 19, locs: 588, delta: +3, quote: 'One bottle of concentrate lasted two months. Fair price for the quality you get.', city: 'Denver LoDo' },
      { theme: 'Speed of service',          share: 13, locs: 512, delta: +2, quote: 'In and out in under ten minutes on a refill run. Line moves fast.', city: 'Houston Galleria' },
      { theme: 'Office cleaning reliability', share: 11, locs: 401, delta: +5, quote: 'Cleaned our office overnight, crew arrived 15 minutes early, spotless by morning.', city: 'Atlanta Midtown' },
    ];
    const negativeThemes = [
      { theme: 'Late arrivals at peak times', share: 34, locs: 392, delta: +3, quote: 'Crew ran 45 minutes late on a Saturday with no ETA updates.', city: 'Las Vegas Strip' },
      { theme: 'Hours inconsistency',      share: 22, locs: 184, delta: -2, quote: 'Google said open till 10, got there at 8:45 and they were already closing down.', city: 'St. Louis Central' },
      { theme: 'Supplies out of stock',     share: 18, locs: 246, delta: +1, quote: 'No concentrate, no refill pods, no sponges at 7pm on a Friday. Really?', city: 'Memphis Beale St.' },
      { theme: 'Parking & access',         share: 15, locs: 142, delta: 0,  quote: 'Lot was full with no signage for overflow. Circled for ten minutes.', city: 'Nashville Broadway' },
      { theme: 'Order accuracy',           share: 11, locs: 168, delta: -1, quote: 'Third time my pickup order was missing an item. Check the bag, please.', city: 'Detroit Corktown' },
    ];

    // Representative quotes (mixed) for the feed.
    const feed = [
      { author: 'Jordan P.', city: 'Austin Downtown', stars: 5, when: '2h', theme: 'Cleaning quality', text: 'Best cleaning crew near the office, hands down. Fast, thorough, and the staff actually know my name.' },
      { author: 'Renee M.',  city: 'Las Vegas Strip', stars: 2, when: '5h', theme: 'Wait times', text: 'The clean was great once the crew arrived, but a 40-minute wait is rough. Needs more hands at peak.' },
      { author: 'Sofia A.',  city: 'Chicago Loop',     stars: 5, when: '1d', theme: 'Office cleaning', text: 'Handled our 60-desk office flawlessly. On time, spotless, zero stress for me.' },
      { author: 'Will T.',   city: 'St. Louis Central', stars: 3, when: '1d', theme: 'Hours', text: 'Decent store but the posted hours are never right. Showed up twice to a closed door.' },
      { author: 'Dana K.',   city: 'Denver LoDo',      stars: 5, when: '2d', theme: 'Value', text: 'Great value for the price and everything is actually non-toxic. My go-to store, twice a month.' },
      { author: 'Marcus D.', city: 'Memphis Beale St.', stars: 2, when: '3d', theme: 'Sold out', text: 'Ran out of half the refill line before close. Frustrating when you drive across town for it.' },
    ];

    // Leaderboard, top & bottom by rating among locations with enough reviews.
    const ranked = [...locs]
      .filter(l => (l.reviewsCount || l.reviews || 0) >= 100)
      .sort((a, b) => (b.rating || 0) - (a.rating || 0));
    const top = ranked.slice(0, 5);
    const bottom = ranked.slice(-5).reverse();

    const responseRate = 91;
    const avgResponseHrs = 3.2;
    const unanswered = Math.round(totalReviews * (1 - responseRate / 100) * 0.04);

    return { n, totalReviews, wRating, distCount, positive, neutral, negative, trend, thisMonth, volDelta,
      positiveThemes, negativeThemes, feed, top, bottom, responseRate, avgResponseHrs, unanswered };
  }, [portfolio]);

  const maxVol = Math.max(...A.trend.map(t => t.vol));
  const distMax = Math.max(...Object.values(A.distCount));

  const kpis = [
    { v: A.wRating.toFixed(2), suffix: '★', l: 'Brand Google rating', sub: 'review-weighted, all GBPs', c: 'var(--marigold)' },
    { v: fmt(A.totalReviews), l: 'Total Google reviews', sub: A.n + ' profiles', c: 'var(--ink)' },
    { v: fmt(A.thisMonth), l: 'New this month', sub: (A.volDelta >= 0 ? '+' : '') + A.volDelta + '% vs last mo', c: A.volDelta >= 0 ? 'var(--sage)' : 'var(--terra)' },
    { v: A.positive + '%', l: 'Positive sentiment', sub: '4–5★ share', c: 'var(--sage)' },
    { v: A.responseRate + '%', l: 'Response rate', sub: A.avgResponseHrs + 'h avg reply', c: A.responseRate >= 85 ? 'var(--sage)' : 'var(--marigold)' },
  ];

  return (
    <div>
      {/* AI brand summary */}
      <div className="card card-pad" style={{ display: 'flex', gap: 16, alignItems: 'flex-start', background: 'linear-gradient(135deg, var(--ink) 0%, #2a2a2b 100%)', color: 'var(--cream)', border: 'none', marginBottom: 14 }}>
        <div style={{ width: 40, height: 40, borderRadius: '50%', overflow: 'hidden', flexShrink: 0, background: 'var(--paper)', border: '1.5px solid rgba(250,246,239,.3)' }}>
          <window.LennyLlama size={40} mood="happy" bg="circle"/>
        </div>
        <div style={{ flex: 1 }}>
          <div style={{ fontSize: 11, letterSpacing: '.1em', textTransform: 'uppercase', color: 'rgba(250,246,239,.5)', fontWeight: 700, marginBottom: 6 }}>What customers are saying · brand-wide</div>
          <div style={{ fontSize: 14.5, lineHeight: 1.6, color: 'var(--cream)' }}>
            Across {A.n} Google Business Profiles, FreshNest holds a <strong style={{ color: 'var(--marigold)' }}>{A.wRating.toFixed(2)}★</strong> average on <strong>{fmt(A.totalReviews)}</strong> reviews, trending up. Customers consistently praise <strong style={{ color: 'var(--sage)' }}>food freshness</strong> and <strong style={{ color: 'var(--sage)' }}>friendly staff</strong>. The one recurring drag, <strong style={{ color: '#f6a663' }}>wait times at peak hours</strong>, shows up at {A.negativeThemes[0].locs} locations and is the clearest system-wide opportunity.
          </div>
        </div>
      </div>

      {/* KPI band */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(5, 1fr)', gap: 10 }}>
        {kpis.map((k, i) => (
          <div key={i} className="card card-pad" style={{ padding: '14px 16px' }}>
            <div style={{ fontFamily: 'var(--ff-display)', fontSize: 27, fontWeight: 500, color: k.c, lineHeight: 1 }}>{k.v}<span style={{ fontSize: 17 }}>{k.suffix || ''}</span></div>
            <div style={{ fontSize: 10, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: '.07em', fontWeight: 600, marginTop: 8 }}>{k.l}</div>
            <div style={{ fontSize: 10.5, color: 'var(--ink-3)', marginTop: 3 }}>{k.sub}</div>
          </div>
        ))}
      </div>

      <SourceNote>Source: Google Business Profile</SourceNote>

      {/* Rating distribution + volume trend */}
      <div style={{ display: 'grid', gridTemplateColumns: '0.9fr 1.4fr', gap: 12, marginTop: 14 }}>
        <div className="card card-pad">
          <div style={{ fontSize: 11, fontWeight: 700, letterSpacing: '.08em', textTransform: 'uppercase', color: 'var(--ink-3)', marginBottom: 14 }}>Rating distribution</div>
          {[5, 4, 3, 2, 1].map(s => {
            const c = A.distCount[s];
            const pct = Math.round(c / A.totalReviews * 100);
            return (
              <div key={s} style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 9 }}>
                <span style={{ width: 30, fontSize: 12, color: 'var(--ink-3)', display: 'flex', alignItems: 'center', gap: 2 }}>{s}<span style={{ color: 'var(--marigold)' }}>★</span></span>
                <div style={{ flex: 1, height: 10, background: 'var(--cream-2)', borderRadius: 5, overflow: 'hidden' }}>
                  <div style={{ width: (c / distMax * 100) + '%', height: '100%', background: s >= 4 ? 'var(--sage)' : s === 3 ? 'var(--marigold)' : 'var(--terra)', borderRadius: 5 }}/>
                </div>
                <span style={{ width: 64, textAlign: 'right', fontSize: 11.5, color: 'var(--ink-3)' }}><span className="mono" style={{ fontWeight: 700, color: 'var(--ink)' }}>{pct}%</span> <span style={{ color: 'var(--ink-4)' }}>{fmt(c)}</span></span>
              </div>
            );
          })}
        </div>

        <div className="card card-pad">
          <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 14 }}>
            <div style={{ fontSize: 11, fontWeight: 700, letterSpacing: '.08em', textTransform: 'uppercase', color: 'var(--ink-3)' }}>Review volume & rating · 12 months</div>
            <div style={{ display: 'flex', gap: 14, fontSize: 10.5, color: 'var(--ink-4)' }}>
              <span style={{ display: 'flex', alignItems: 'center', gap: 5 }}><span style={{ width: 9, height: 9, borderRadius: 2, background: 'var(--sky)' }}/>Volume</span>
              <span style={{ display: 'flex', alignItems: 'center', gap: 5 }}><span style={{ width: 9, height: 3, borderRadius: 2, background: 'var(--marigold)' }}/>Rating</span>
            </div>
          </div>
          <div style={{ position: 'relative', display: 'flex', alignItems: 'flex-end', gap: 7, height: 130 }}>
            {A.trend.map((t, i) => (
              <div key={i} style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 5 }}>
                <div style={{ width: '100%', height: (t.vol / maxVol * 104) + 'px', background: 'linear-gradient(to top, var(--sky), var(--sky-soft))', borderRadius: '4px 4px 0 0' }} title={t.vol + ' reviews'}/>
                <span style={{ fontSize: 9, color: 'var(--ink-4)', fontFamily: 'var(--ff-mono)' }}>{t.m}</span>
              </div>
            ))}
            {/* rating line overlay */}
            <svg viewBox="0 0 100 100" preserveAspectRatio="none" style={{ position: 'absolute', inset: 0, width: '100%', height: 'calc(100% - 16px)', pointerEvents: 'none' }}>
              <polyline fill="none" stroke="var(--marigold)" strokeWidth="1.4" vectorEffect="non-scaling-stroke"
                points={A.trend.map((t, i) => {
                  const x = (i + 0.5) / A.trend.length * 100;
                  const lo = A.wRating - 0.4, hi = A.wRating + 0.2;
                  const y = 100 - ((t.rating - lo) / (hi - lo)) * 80 - 8;
                  return `${x},${Math.max(2, Math.min(98, y))}`;
                }).join(' ')}/>
            </svg>
          </div>
        </div>
      </div>

      <SourceNote>Source: Google Business Profile</SourceNote>

      {/* Sentiment strip */}
      <Label hint="4–5★ positive · 3★ neutral · 1–2★ negative">Sentiment mix</Label>
      <div className="card card-pad">
        <div style={{ display: 'flex', height: 16, borderRadius: 999, overflow: 'hidden', marginBottom: 14 }}>
          <div style={{ width: A.positive + '%', background: 'var(--sage)' }}/>
          <div style={{ width: A.neutral + '%', background: 'var(--marigold)' }}/>
          <div style={{ width: A.negative + '%', background: 'var(--terra)' }}/>
        </div>
        <div style={{ display: 'flex', gap: 32 }}>
          {[['Positive', A.positive, 'var(--sage)'], ['Neutral', A.neutral, 'var(--marigold)'], ['Negative', A.negative, 'var(--terra)']].map(([l, v, c]) => (
            <div key={l} style={{ display: 'flex', alignItems: 'center', gap: 9 }}>
              <span style={{ width: 10, height: 10, borderRadius: 3, background: c }}/>
              <span style={{ fontFamily: 'var(--ff-display)', fontSize: 22, fontWeight: 500, color: 'var(--ink)' }}>{v}%</span>
              <span style={{ fontSize: 12, color: 'var(--ink-3)' }}>{l}</span>
            </div>
          ))}
        </div>
      </div>

      <SourceNote>Source: Google Business Profile</SourceNote>

      {/* Themes: what people love / what needs work */}
      <Label hint="ranked by mention share across all GBPs">What customers are talking about</Label>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
        <ThemeColumn title="What they love" tone="ok" themes={A.positiveThemes}/>
        <ThemeColumn title="What needs work" tone="bad" themes={A.negativeThemes}/>
      </div>

      <SourceNote>Source: Google Business Profile · themes extracted by LOCALACT</SourceNote>

      {/* Representative reviews */}
      <Label hint="auto-selected, brand-representative">Representative reviews</Label>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
        {A.feed.map((r, i) => (
          <div key={i} className="card card-pad" style={{ padding: 16 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 8 }}>
              <div style={{ width: 30, height: 30, borderRadius: '50%', background: 'var(--cream-2)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 12, fontWeight: 700, color: 'var(--ink-2)' }}>{r.author[0]}</div>
              <div style={{ flex: 1 }}>
                <div style={{ fontSize: 12.5, fontWeight: 600, color: 'var(--ink)' }}>{r.author}</div>
                <div style={{ fontSize: 10.5, color: 'var(--ink-4)' }}>{r.city} · {r.when} ago · Google</div>
              </div>
              <Stars n={r.stars}/>
            </div>
            <div style={{ fontSize: 12.5, color: 'var(--ink-2)', lineHeight: 1.55, marginBottom: 9 }}>"{r.text}"</div>
            <Pill tone={r.stars >= 4 ? 'ok' : r.stars === 3 ? 'warn' : 'bad'}>{r.theme}</Pill>
          </div>
        ))}
      </div>

      <SourceNote>Source: Google Business Profile</SourceNote>

      {/* Leaderboard */}
      <Label hint="locations with 100+ reviews">Rating leaders & laggards</Label>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
        <LeaderCard title="Top rated" rows={A.top} onOpen={onOpen} good/>
        <LeaderCard title="Needs attention" rows={A.bottom} onOpen={onOpen}/>
      </div>
    </div>
  );
}

function ThemeColumn({ title, tone, themes }) {
  const accent = tone === 'ok' ? 'var(--sage)' : 'var(--terra)';
  return (
    <div className="card" style={{ overflow: 'hidden' }}>
      <div style={{ padding: '13px 16px', borderBottom: '1px solid var(--cream-2)', display: 'flex', alignItems: 'center', gap: 8 }}>
        <span style={{ width: 9, height: 9, borderRadius: '50%', background: accent }}/>
        <span style={{ fontSize: 12.5, fontWeight: 700, color: 'var(--ink)' }}>{title}</span>
      </div>
      {themes.map((t, i) => (
        <div key={i} style={{ padding: '13px 16px', borderBottom: i === themes.length - 1 ? 'none' : '1px solid var(--cream-2)' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 7 }}>
            <span style={{ flex: 1, fontSize: 13, fontWeight: 600, color: 'var(--ink)' }}>{t.theme}</span>
            <span style={{ fontSize: 11, color: t.delta > 0 ? (tone === 'ok' ? 'var(--sage)' : 'var(--terra)') : t.delta < 0 ? (tone === 'ok' ? 'var(--terra)' : 'var(--sage)') : 'var(--ink-4)', fontWeight: 700 }}>
              {t.delta > 0 ? '↑' : t.delta < 0 ? '↓' : '–'} {Math.abs(t.delta)}%
            </span>
            <span className="mono" style={{ fontSize: 12, fontWeight: 700, color: accent, width: 36, textAlign: 'right' }}>{t.share}%</span>
          </div>
          <div style={{ height: 6, background: 'var(--cream-2)', borderRadius: 3, overflow: 'hidden', marginBottom: 8 }}>
            <div style={{ width: t.share + '%', height: '100%', background: accent }}/>
          </div>
          <div style={{ fontSize: 11.5, color: 'var(--ink-3)', lineHeight: 1.5, fontStyle: 'italic' }}>"{t.quote}"</div>
          <div style={{ fontSize: 10.5, color: 'var(--ink-4)', marginTop: 5 }}>{t.locs} locations · e.g. {t.city}</div>
        </div>
      ))}
    </div>
  );
}

function LeaderCard({ title, rows, onOpen, good }) {
  return (
    <div className="card" style={{ overflow: 'hidden' }}>
      <div style={{ padding: '13px 16px', borderBottom: '1px solid var(--cream-2)', display: 'flex', alignItems: 'center', gap: 8 }}>
        <span style={{ width: 9, height: 9, borderRadius: '50%', background: good ? 'var(--sage)' : 'var(--terra)' }}/>
        <span style={{ fontSize: 12.5, fontWeight: 700, color: 'var(--ink)' }}>{title}</span>
      </div>
      {rows.map((l, i) => (
        <div key={l.unit} onClick={() => onOpen(l)} className="loc-row"
             style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '11px 16px', borderBottom: i === rows.length - 1 ? 'none' : '1px solid var(--cream-2)', cursor: 'pointer' }}>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 12.5, fontWeight: 600, color: 'var(--ink)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{l.unit}</div>
            <div style={{ fontSize: 10.5, color: 'var(--ink-4)' }}>{l.city} · {fmt(l.reviewsCount || l.reviews || 0)} reviews</div>
          </div>
          <Stars n={Math.round(l.rating || 0)} size={12}/>
          <span className="mono" style={{ fontSize: 14, fontWeight: 700, color: (l.rating || 0) >= 4.3 ? 'var(--sage)' : (l.rating || 0) >= 3.9 ? 'var(--marigold)' : 'var(--terra)', width: 30, textAlign: 'right' }}>{(l.rating || 0).toFixed(1)}</span>
        </div>
      ))}
    </div>
  );
}

window.HqReviewAnalysis = HqReviewAnalysis;
})();
