/* Google Reviews → Discount codes. */

const { useCallback } = React;
const _j = { "Content-Type": "application/json" };

function apiR(path, method = "GET", body) {
  return fetch(path, {
    method,
    headers: body !== undefined ? _j : undefined,
    body: body !== undefined ? JSON.stringify(body) : undefined,
  }).then(async r => {
    if (!r.ok) { let m; try { m = (await r.json()).error; } catch {} throw new Error(m || r.status + " " + r.statusText); }
    return r.json();
  });
}

/* ── Tiny helpers ─────────────────────────────────────────────── */

function Stars({ n }) {
  const v = Math.round(n || 0);
  return <span style={{ color: "#f59e0b", fontSize: 13, letterSpacing: 0 }}>{"★".repeat(v)}{"☆".repeat(5 - v)}</span>;
}

const S_COLOR = { unmatched: "#9ca3af", matched: "#3b82f6", sent: "#f97316", used: "#22c55e" };
const S_LABEL = { unmatched: "Unmatched", matched: "Ready to send", sent: "Sent", used: "Used" };

function Pill({ status }) {
  const c = S_COLOR[status] || S_COLOR.unmatched;
  return (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 5, fontSize: 11, fontWeight: 600, color: c }}>
      <span style={{ width: 6, height: 6, borderRadius: "50%", background: c, flexShrink: 0 }} />
      {S_LABEL[status] || status}
    </span>
  );
}

/* Primary mint button */
function MintBtn({ children, onClick, loading, disabled }) {
  return (
    <button onClick={onClick} disabled={disabled || loading}
      style={{ display: "inline-flex", alignItems: "center", gap: 6, background: "#18f4af", color: "#00271a", border: "none",
               borderRadius: 7, padding: "7px 14px", fontSize: 12, fontWeight: 700, cursor: "pointer", whiteSpace: "nowrap",
               opacity: (disabled || loading) ? 0.5 : 1 }}>
      {loading ? <span className="spin spin--dark" style={{ width: 12, height: 12 }} /> : children}
    </button>
  );
}

/* Ghost / secondary button */
function GhostBtn({ children, onClick, loading, disabled, danger }) {
  return (
    <button onClick={onClick} disabled={disabled || loading}
      style={{ display: "inline-flex", alignItems: "center", gap: 4, background: "none", border: "none",
               color: danger ? "#ef4444" : "#6b7280", fontSize: 11, fontWeight: 500, cursor: "pointer",
               padding: "2px 4px", borderRadius: 4, whiteSpace: "nowrap",
               opacity: (disabled || loading) ? 0.4 : 1 }}>
      {loading ? <span className="spin" style={{ width: 10, height: 10 }} /> : children}
    </button>
  );
}

/* ── Customer search modal ────────────────────────────────────── */

function CustomerSearchModal({ review, onLink, onClose }) {
  const [q, setQ] = useState(review.reviewerName || "");
  const [results, setResults] = useState(null);
  const [loading, setLoading] = useState(false);
  const [err, setErr] = useState(null);
  const [email, setEmail] = useState("");
  const [manualName, setManualName] = useState(review.reviewerName || "");

  const search = useCallback(async () => {
    if (!q.trim()) return;
    setLoading(true); setErr(null);
    try { const r = await apiR("/api/reviews/customers?q=" + encodeURIComponent(q)); setResults(r.customers || []); }
    catch (e) { setErr(e.message); }
    finally { setLoading(false); }
  }, [q]);

  useEffect(() => { search(); }, []);

  return (
    <div className="modal-overlay" onClick={onClose}>
      <div className="modal" style={{ maxWidth: 460, padding: 24, borderRadius: 12 }} onClick={e => e.stopPropagation()}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 18 }}>
          <div>
            <div style={{ fontWeight: 700, fontSize: 15 }}>Link customer</div>
            <div style={{ fontSize: 12, color: "#9ca3af", marginTop: 2 }}>for review by {review.reviewerName}</div>
          </div>
          <button className="icon-btn" onClick={onClose}><Icon name="x" /></button>
        </div>

        <div style={{ display: "flex", gap: 8, marginBottom: 14 }}>
          <input className="input" value={q} onChange={e => setQ(e.target.value)}
            placeholder="Search by name or email…" style={{ flex: 1, fontSize: 13 }}
            onKeyDown={e => e.key === "Enter" && search()} />
          <button className="btn btn--dark" style={{ padding: "0 14px", fontSize: 13 }}
            onClick={search} disabled={loading}>
            {loading ? <span className="spin spin--light" style={{ width: 12, height: 12 }} /> : "Search"}
          </button>
        </div>

        {err && <div style={{ color: "#ef4444", fontSize: 12, marginBottom: 10 }}>{err}</div>}

        <div style={{ maxHeight: 220, overflowY: "auto" }}>
          {results !== null && results.length === 0 && (
            <div style={{ textAlign: "center", padding: "20px 0", color: "#9ca3af", fontSize: 13 }}>No customers found</div>
          )}
          {(results || []).map(c => (
            <div key={c.id || c.email} style={{ display: "flex", alignItems: "center", gap: 10, padding: "9px 0", borderBottom: "1px solid #f3f4f6" }}>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontWeight: 600, fontSize: 13, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{c.name}</div>
                <div style={{ fontSize: 11, color: "#9ca3af" }}>{c.email} · {c.ordersCount} orders</div>
              </div>
              <MintBtn onClick={() => onLink(c)}>Link</MintBtn>
            </div>
          ))}
        </div>

        <div style={{ marginTop: 16, paddingTop: 14, borderTop: "1px solid #f3f4f6" }}>
          <div style={{ fontSize: 12, color: "#9ca3af", marginBottom: 8 }}>Or enter email manually</div>
          <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
            <input className="input" value={manualName} onChange={e => setManualName(e.target.value)}
              placeholder="Name" style={{ flex: 1, minWidth: 110, fontSize: 12 }} />
            <input className="input" value={email} onChange={e => setEmail(e.target.value)}
              placeholder="Email address" type="email" style={{ flex: 2, minWidth: 150, fontSize: 12 }} />
            <MintBtn disabled={!email.includes("@")} onClick={() => onLink({ id: null, name: manualName, email, ordersCount: 0 })}>
              Use
            </MintBtn>
          </div>
        </div>
      </div>
    </div>
  );
}

/* ── Review card ──────────────────────────────────────────────── */

function ReviewCard({ review, onRefresh }) {
  const [busy, setBusy] = useState(null);
  const [err, setErr] = useState(null);
  const [showLink, setShowLink] = useState(false);
  const [showNote, setShowNote] = useState(false);
  const [notes, setNotes] = useState(review.notes || "");

  const act = useCallback(async (action, method = "POST", body) => {
    setBusy(action); setErr(null);
    try { await apiR(`/api/reviews/${review.id}/${action}`, method, body); await onRefresh(); }
    catch (e) { setErr(e.message); }
    finally { setBusy(null); }
  }, [review.id, onRefresh]);

  // Delete hits the bare resource (DELETE /api/reviews/:id) — no action suffix.
  const remove = useCallback(async () => {
    setBusy("delete"); setErr(null);
    try { await apiR(`/api/reviews/${review.id}`, "DELETE"); await onRefresh(); }
    catch (e) { setErr(e.message); }
    finally { setBusy(null); }
  }, [review.id, onRefresh]);

  const linkCustomer = useCallback(async (c) => {
    setBusy("match"); setErr(null);
    try {
      await apiR(`/api/reviews/${review.id}/match`, "POST", { customerId: c.id, customerEmail: c.email, customerName: c.name });
      setShowLink(false); await onRefresh();
    } catch (e) { setErr(e.message); }
    finally { setBusy(null); }
  }, [review.id, onRefresh]);

  const dateStr = review.reviewPublishedAt
    ? new Date(review.reviewPublishedAt).toLocaleDateString("en-GB", { day: "numeric", month: "short", year: "numeric" })
    : "";

  const borderColor = S_COLOR[review.status] || S_COLOR.unmatched;

  // Primary action button
  let primary = null;
  if (review.status === "matched" || (review.customerEmail && !review.discountCode)) {
    primary = <MintBtn loading={busy === "issue"} onClick={() => act("issue")}>Issue & Send</MintBtn>;
  } else if (!review.customerEmail) {
    primary = <MintBtn onClick={() => setShowLink(true)}>Link customer</MintBtn>;
  }

  return (
    <>
    <div style={{
      background: "#fff", borderRadius: 10, marginBottom: 8,
      border: "1px solid #e5e7eb",
      borderLeft: `3px solid ${borderColor}`,
      padding: "14px 16px",
      display: "grid",
      gridTemplateColumns: "180px 1fr 160px 180px",
      gap: 16,
      alignItems: "start",
    }}>

      {/* Col 1 — Reviewer */}
      <div>
        <div style={{ fontWeight: 700, fontSize: 14, color: "#111", marginBottom: 1 }}>{review.reviewerName}</div>
        <div style={{ fontSize: 11, color: "#9ca3af", marginBottom: 4 }}>{dateStr}</div>
        <Stars n={review.reviewRating} />
        <div style={{ marginTop: 6 }}><Pill status={review.status} /></div>
        {(review.followups || []).length > 0 && !review.discountUsed && (
          <div style={{ fontSize: 10, color: "#9ca3af", marginTop: 3 }}>
            {(review.followups || []).length} follow-up{(review.followups || []).length !== 1 ? "s" : ""} sent
          </div>
        )}
      </div>

      {/* Col 2 — Review text */}
      <div style={{ fontSize: 13, color: "#4b5563", lineHeight: 1.55,
                    display: "-webkit-box", WebkitLineClamp: 3, WebkitBoxOrient: "vertical", overflow: "hidden" }}>
        {review.reviewText || <em style={{ color: "#9ca3af" }}>No review text</em>}
      </div>

      {/* Col 3 — Customer */}
      <div>
        {review.customerEmail ? (
          <>
            <div style={{ fontWeight: 600, fontSize: 13, color: "#111", marginBottom: 1 }}>{review.customerName || "—"}</div>
            <div style={{ fontSize: 11, color: "#9ca3af", marginBottom: 4 }}>{review.customerEmail}</div>
            <GhostBtn onClick={() => act("unlink", "POST")} loading={busy === "unlink"}>Unlink</GhostBtn>
          </>
        ) : (
          <button onClick={() => setShowLink(true)}
            style={{ background: "none", border: "1px dashed #d1d5db", borderRadius: 6, padding: "6px 12px",
                     fontSize: 12, color: "#6b7280", cursor: "pointer", width: "100%" }}>
            + Link customer
          </button>
        )}
      </div>

      {/* Col 4 — Discount code + actions */}
      <div>
        {/* Discount code */}
        {review.discountCode ? (
          <div style={{ marginBottom: 8 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 4, flexWrap: "wrap" }}>
              <span style={{ fontFamily: "monospace", fontWeight: 700, fontSize: 13, color: "#111",
                             background: "#f3f4f6", padding: "3px 8px", borderRadius: 5 }}>
                {review.discountCode}
              </span>
              <CopyBtn text={review.discountCode} title="Copy code" />
              <CopyBtn text={review.discountShareUrl || `https://dtf.uk/discount/${review.discountCode}`} title="Copy public discount link (dtf.uk/discount/…)" />
              {review.discountAdminLink && (
                <a href={review.discountAdminLink} target="_blank" rel="noopener" title="Open discount in Shopify admin"
                   style={{ fontSize: 10, color: "#9ca3af", textDecoration: "underline" }}>↗</a>
              )}
            </div>
            {review.discountUsed && (
              <div style={{ fontSize: 10, color: "#22c55e", marginTop: 3, fontWeight: 600 }}>
                {review.discountUsedManual ? "✓ Marked used" : "✓ Redeemed in Shopify"}
                {review.discountUsedAt ? ` · ${new Date(review.discountUsedAt).toLocaleDateString("en-GB")}` : ""}
              </div>
            )}
          </div>
        ) : (
          <div style={{ fontSize: 11, color: "#d1d5db", fontFamily: "monospace", marginBottom: 8 }}>— no code yet —</div>
        )}

        {/* Primary action */}
        {primary && <div style={{ marginBottom: 6 }}>{primary}</div>}

        {/* Secondary actions row */}
        <div style={{ display: "flex", flexWrap: "wrap", gap: 2, marginTop: 2 }}>
          {review.discountCode && review.customerEmail && (
            <GhostBtn loading={busy === "resend"} onClick={() => act("resend")}>Resend</GhostBtn>
          )}
          {review.discountCode && review.customerEmail && (
            <GhostBtn loading={busy === "reissue"} onClick={() => { if (confirm("Void old code and create a new one?")) act("reissue"); }}>Re-issue</GhostBtn>
          )}
          {!review.discountUsed && review.discountCode && (
            <GhostBtn loading={busy === "mark-used"} onClick={() => act("mark-used")}>Mark used</GhostBtn>
          )}
          {review.discountUsed && review.discountUsedManual && (
            <GhostBtn loading={busy === "mark-unused"} onClick={() => act("mark-unused")}>Unmark</GhostBtn>
          )}
          {review.status === "sent" && !review.followupStopped && (
            <GhostBtn loading={busy === "stop-followups"} onClick={() => act("stop-followups")}>Stop follow-ups</GhostBtn>
          )}
          <GhostBtn onClick={() => setShowNote(v => !v)}>{showNote ? "Hide note" : (review.notes ? "Note ✎" : "Note")}</GhostBtn>
          <GhostBtn danger onClick={() => remove()}>Delete</GhostBtn>
        </div>

        {err && <div style={{ fontSize: 11, color: "#ef4444", marginTop: 6 }}>{err}</div>}
      </div>
    </div>

    {/* Notes inline */}
    {showNote && (
      <div style={{ background: "#fffbeb", border: "1px solid #fde68a", borderRadius: 8, padding: "10px 14px", marginBottom: 8, display: "flex", gap: 8 }}>
        <textarea className="input" rows={2} value={notes} onChange={e => setNotes(e.target.value)}
          placeholder="Internal note…" style={{ flex: 1, fontSize: 12, resize: "vertical", background: "transparent", border: "1px solid #fde68a" }} />
        <button className="btn btn--ghost" style={{ fontSize: 12, padding: "4px 12px", alignSelf: "flex-end" }}
          onClick={async () => { await act("notes", "PATCH", { notes }); setShowNote(false); }}
          disabled={busy === "notes"}>
          {busy === "notes" ? <span className="spin" style={{ width: 12, height: 12 }} /> : "Save"}
        </button>
      </div>
    )}

    {showLink && <CustomerSearchModal review={review} onLink={linkCustomer} onClose={() => setShowLink(false)} />}
    </>
  );
}

/* ── Manual review add modal ──────────────────────────────────── */

function AddReviewModal({ onSaved, onClose }) {
  const [name, setName] = useState("");
  const [rating, setRating] = useState(5);
  const [text, setText] = useState("");
  const [date, setDate] = useState("");
  const [busy, setBusy] = useState(false);
  const [err, setErr] = useState(null);

  const save = useCallback(async () => {
    if (!name.trim()) { setErr("Reviewer name is required"); return; }
    setBusy(true); setErr(null);
    try {
      await apiR("/api/reviews/manual", "POST", {
        reviewerName: name.trim(), reviewRating: rating,
        reviewText: text.trim(), reviewDate: date || undefined,
      });
      onSaved();
    } catch (e) { setErr(e.message); }
    finally { setBusy(false); }
  }, [name, rating, text, date, onSaved]);

  return (
    <div className="modal-overlay" onClick={onClose}>
      <div className="modal" style={{ maxWidth: 420, padding: 24, borderRadius: 12 }} onClick={e => e.stopPropagation()}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 20 }}>
          <div style={{ fontWeight: 700, fontSize: 15 }}>Add review manually</div>
          <button className="icon-btn" onClick={onClose}><Icon name="x" /></button>
        </div>

        <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
          <div>
            <label style={{ fontSize: 12, fontWeight: 600, color: "#6b7280", display: "block", marginBottom: 4 }}>Reviewer name *</label>
            <input className="input" value={name} onChange={e => setName(e.target.value)}
              placeholder="e.g. John Smith" style={{ width: "100%", fontSize: 13 }} />
          </div>

          <div>
            <label style={{ fontSize: 12, fontWeight: 600, color: "#6b7280", display: "block", marginBottom: 4 }}>Rating</label>
            <div style={{ display: "flex", gap: 8 }}>
              {[1,2,3,4,5].map(n => (
                <button key={n} onClick={() => setRating(n)}
                  style={{ background: "none", border: "none", fontSize: 22, cursor: "pointer",
                           color: n <= rating ? "#f59e0b" : "#d1d5db" }}>★</button>
              ))}
            </div>
          </div>

          <div>
            <label style={{ fontSize: 12, fontWeight: 600, color: "#6b7280", display: "block", marginBottom: 4 }}>Review text</label>
            <textarea className="input" rows={3} value={text} onChange={e => setText(e.target.value)}
              placeholder="Optional — paste the review text" style={{ width: "100%", fontSize: 13, resize: "vertical" }} />
          </div>

          <div>
            <label style={{ fontSize: 12, fontWeight: 600, color: "#6b7280", display: "block", marginBottom: 4 }}>Review date (optional)</label>
            <input className="input" type="date" value={date} onChange={e => setDate(e.target.value)}
              style={{ width: "100%", fontSize: 13 }} />
          </div>

          {err && <div style={{ fontSize: 12, color: "#ef4444" }}>{err}</div>}

          <div style={{ display: "flex", justifyContent: "flex-end", gap: 8, marginTop: 4 }}>
            <button className="btn btn--ghost" onClick={onClose} style={{ fontSize: 13 }}>Cancel</button>
            <MintBtn onClick={save} loading={busy} disabled={!name.trim()}>Save review</MintBtn>
          </div>
        </div>
      </div>
    </div>
  );
}

/* ── Main view ────────────────────────────────────────────────── */

function ReviewsView() {
  const [reviews, setReviews] = useState(null);
  const [syncing, setSyncing] = useState(false);
  const [syncResult, setSyncResult] = useState(null);
  const [syncErr, setSyncErr] = useState(null);
  const [filter, setFilter] = useState("all");
  const [loadErr, setLoadErr] = useState(null);
  const [showAdd, setShowAdd] = useState(false);

  const [gbp, setGbp] = useState(null); // Google Business Profile connection status

  const load = useCallback(async () => {
    setLoadErr(null);
    try { const r = await apiR("/api/reviews"); setReviews(r.reviews || []); }
    catch (e) { setLoadErr(e.message); }
  }, []);
  const loadGbp = useCallback(async () => {
    try { setGbp(await apiR("/api/reviews/gbp/status")); } catch { setGbp(null); }
  }, []);

  useEffect(() => { load(); loadGbp(); }, []);

  const sync = useCallback(async () => {
    setSyncing(true); setSyncResult(null); setSyncErr(null);
    try { const r = await apiR("/api/reviews/sync", "POST"); setSyncResult(r); await load(); }
    catch (e) { setSyncErr(e.message); }
    finally { setSyncing(false); }
  }, [load]);

  const [matching, setMatching] = useState(false);
  const autoMatch = useCallback(async () => {
    setMatching(true); setSyncResult(null); setSyncErr(null);
    try { const r = await apiR("/api/reviews/auto-match", "POST"); setSyncResult({ autoMatched: r.matched, checked: r.checked }); await load(); }
    catch (e) { setSyncErr(e.message); }
    finally { setMatching(false); }
  }, [load]);

  const [sending, setSending] = useState(false);
  const sendPending = useCallback(async () => {
    setSending(true); setSyncResult(null); setSyncErr(null);
    try { const r = await apiR("/api/reviews/send-pending", "POST"); setSyncResult({ issued: r.issued, failedCount: (r.failed || []).length }); await load(); }
    catch (e) { setSyncErr(e.message); }
    finally { setSending(false); }
  }, [load]);

  const visible = useMemo(() => {
    if (!reviews) return [];
    if (filter === "all") return reviews;
    if (filter === "used") return reviews.filter(r => r.discountUsed);
    return reviews.filter(r => r.status === filter);
  }, [reviews, filter]);

  const counts = useMemo(() => {
    if (!reviews) return {};
    const c = { all: reviews.length, used: 0 };
    for (const r of reviews) {
      // "used" is its own tab keyed off discountUsed — don't also count it via
      // status, or used reviews get double-counted.
      if (r.status && r.status !== "used") c[r.status] = (c[r.status] || 0) + 1;
      if (r.discountUsed) c.used++;
    }
    return c;
  }, [reviews]);

  const TABS = [
    { key: "all", label: "All" },
    { key: "unmatched", label: "Unmatched" },
    { key: "matched", label: "Ready" },
    { key: "sent", label: "Sent" },
    { key: "used", label: "Used" },
  ];

  return (
    <div style={{ padding: "20px 24px", maxWidth: 1060, margin: "0 auto" }}>

      {/* Header */}
      <div style={{ display: "flex", alignItems: "flex-start", marginBottom: 20 }}>
        <div>
          <h2 style={{ margin: 0, fontSize: 20, fontWeight: 800, color: "#111" }}>Google Reviews</h2>
          <p style={{ margin: "3px 0 0", fontSize: 13, color: "#9ca3af" }}>
            20% single-use discount codes for customers who leave a review
          </p>
        </div>
        <div style={{ marginLeft: "auto", display: "flex", gap: 8 }}>
          <button onClick={() => setShowAdd(true)}
            style={{ display: "inline-flex", alignItems: "center", gap: 6, background: "#f3f4f6", color: "#374151",
                     border: "1px solid #e5e7eb", borderRadius: 8, padding: "9px 16px", fontSize: 13, fontWeight: 600,
                     cursor: "pointer" }}>
            + Add manually
          </button>
          <button onClick={autoMatch} disabled={matching}
            style={{ display: "inline-flex", alignItems: "center", gap: 6, background: "#f3f4f6", color: "#374151",
                     border: "1px solid #e5e7eb", borderRadius: 8, padding: "9px 16px", fontSize: 13, fontWeight: 600,
                     cursor: "pointer", opacity: matching ? 0.6 : 1 }}>
            {matching ? <><span className="spin spin--dark" style={{ width: 13, height: 13 }} /> Matching…</> : "Auto-match customers"}
          </button>
          <button onClick={sendPending} disabled={sending}
            style={{ display: "inline-flex", alignItems: "center", gap: 6, background: "#f3f4f6", color: "#374151",
                     border: "1px solid #e5e7eb", borderRadius: 8, padding: "9px 16px", fontSize: 13, fontWeight: 600,
                     cursor: "pointer", opacity: sending ? 0.6 : 1 }}>
            {sending ? <><span className="spin spin--dark" style={{ width: 13, height: 13 }} /> Sending…</> : "Send to matched"}
          </button>
          <button onClick={sync} disabled={syncing}
            style={{ display: "inline-flex", alignItems: "center", gap: 7, background: "#18f4af", color: "#00271a",
                     border: "none", borderRadius: 8, padding: "9px 18px", fontSize: 13, fontWeight: 700,
                     cursor: "pointer", opacity: syncing ? 0.6 : 1 }}>
            {syncing ? <><span className="spin spin--dark" style={{ width: 13, height: 13 }} /> Syncing…</> : <><Icon name="refresh" />Sync reviews</>}
          </button>
        </div>
      </div>

      {/* Review source: Google Business Profile (full) vs Places (5-review cap) */}
      {gbp && gbp.connected ? (
        <div style={{ background: "#ecfdf5", border: "1px solid #a7f3d0", borderRadius: 8, padding: "9px 14px",
                      marginBottom: 14, fontSize: 12, color: "#065f46", display: "flex", gap: 8, alignItems: "center" }}>
          <span style={{ fontWeight: 700 }}>✓</span>
          <span style={{ flex: 1 }}>
            <strong>Google Business Profile connected</strong>{gbp.locationTitle ? ` — ${gbp.locationTitle}` : ""}. <strong>Sync</strong> now pulls <strong>all</strong> reviews, newest first.
          </span>
          <button onClick={async () => { if (confirm("Disconnect Google Business Profile? Sync will fall back to the 5-review Places API.")) { try { await apiR("/api/reviews/gbp/disconnect", "POST"); loadGbp(); } catch (e) { alert(e.message); } } }}
            style={{ background: "transparent", border: "1px solid #a7f3d0", color: "#065f46", borderRadius: 6, padding: "4px 10px", fontSize: 11.5, fontWeight: 600, cursor: "pointer" }}>Disconnect</button>
        </div>
      ) : (
        <div style={{ background: "#fffbeb", border: "1px solid #fde68a", borderRadius: 8, padding: "9px 14px",
                      marginBottom: 14, fontSize: 12, color: "#92400e", display: "flex", gap: 8, alignItems: "center" }}>
          <span style={{ fontWeight: 700, flexShrink: 0 }}>ℹ</span>
          <span style={{ flex: 1 }}>
            <strong>Sync</strong> only fetches the 5 most-recent-by-relevance Google reviews (Places API limit), so new reviews often don't appear.
            {gbp && gbp.oauthConfigured
              ? <> Connect your <strong>Google Business Profile</strong> to sync <strong>all</strong> reviews automatically.</>
              : <> Use <strong>Add manually</strong> for now. (Connecting the Business Profile API needs OAuth creds in <code>.env</code> first.)</>}
          </span>
          {gbp && gbp.oauthConfigured &&
            <a href="/api/reviews/gbp/connect"
               style={{ background: "#18f4af", color: "#00271a", border: "none", borderRadius: 6, padding: "6px 12px", fontSize: 12, fontWeight: 700, textDecoration: "none", whiteSpace: "nowrap" }}>Connect Google Business Profile</a>}
        </div>
      )}

      {/* GBP connected but its API isn't usable yet (quota 0 / access not approved) */}
      {syncResult && syncResult.gbpError && (
        <div style={{ background: "#fff7ed", border: "1px solid #fed7aa", borderRadius: 8, padding: "9px 14px",
                      marginBottom: 14, fontSize: 12, color: "#9a3412" }}>
          <strong>Business Profile sync isn't available yet</strong> — Google returned: <span style={{ fontFamily: "monospace" }}>{syncResult.gbpError}</span>. This is normal until your <strong>GBP API access request is approved</strong> (quota is 0 until then). Synced via Places (5) for now; it'll switch to all reviews automatically once approved.
        </div>
      )}

      {/* Toast messages */}
      {syncResult && (
        <div style={{ display: "flex", alignItems: "center", gap: 10, background: "#f0fdf4", border: "1px solid #bbf7d0",
                      borderRadius: 8, padding: "10px 14px", marginBottom: 14, fontSize: 13, color: "#166534" }}>
          <Icon name="check" />
          <span>
            {syncResult.issued !== undefined ? (
              <>Sent — <strong>{syncResult.issued}</strong> discount{syncResult.issued !== 1 ? "s" : ""} issued & emailed{syncResult.failedCount > 0 ? `, ${syncResult.failedCount} failed` : ""}</>
            ) : syncResult.autoMatched !== undefined ? (
              <>Auto-matched — <strong>{syncResult.autoMatched}</strong> review{syncResult.autoMatched !== 1 ? "s" : ""} linked to customers{typeof syncResult.checked === "number" ? ` (${syncResult.checked} checked)` : ""}</>
            ) : (
              <>Synced — <strong>{syncResult.added}</strong> new review{syncResult.added !== 1 ? "s" : ""}
              {syncResult.added > 0 && syncResult.autoMatched ? `, ${syncResult.autoMatched} matched` : ""}
              {syncResult.issued ? `, ${syncResult.issued} emailed` : ""}
              {syncResult.marked > 0 ? `, ${syncResult.marked} marked used` : ""}</>
            )}
          </span>
        </div>
      )}
      {syncErr && (
        <div style={{ background: "#fef2f2", border: "1px solid #fecaca", borderRadius: 8, padding: "10px 14px",
                      marginBottom: 14, fontSize: 13, color: "#991b1b" }}>
          <strong>Sync failed:</strong> {syncErr}
        </div>
      )}
      {loadErr && <div style={{ color: "#ef4444", fontSize: 13, marginBottom: 12 }}>{loadErr}</div>}

      {/* Filter tabs */}
      <div style={{ display: "flex", gap: 4, marginBottom: 16, borderBottom: "1px solid #e5e7eb", paddingBottom: 0 }}>
        {TABS.map(f => {
          const cnt = counts[f.key];
          const active = filter === f.key;
          return (
            <button key={f.key} onClick={() => setFilter(f.key)}
              style={{ background: "none", border: "none", borderBottom: active ? "2px solid #18f4af" : "2px solid transparent",
                       padding: "8px 12px", fontSize: 13, fontWeight: active ? 700 : 400, color: active ? "#111" : "#6b7280",
                       cursor: "pointer", marginBottom: -1, whiteSpace: "nowrap" }}>
              {f.label}
              {cnt != null && cnt > 0 && (
                <span style={{ marginLeft: 5, background: active ? "#18f4af" : "#f3f4f6",
                               color: active ? "#00271a" : "#6b7280",
                               borderRadius: 10, padding: "1px 6px", fontSize: 11, fontWeight: 700 }}>
                  {cnt}
                </span>
              )}
            </button>
          );
        })}
      </div>

      {/* Cards */}
      {reviews === null ? (
        <SkeletonRows rows={3} />
      ) : visible.length === 0 ? (
        <div style={{ textAlign: "center", padding: "56px 0", color: "#9ca3af" }}>
          <div style={{ fontSize: 32, marginBottom: 8 }}>★</div>
          <div style={{ fontSize: 14 }}>
            {filter === "all" ? "No reviews yet — click Sync reviews to fetch from Google" : `No ${filter} reviews`}
          </div>
        </div>
      ) : (
        <div>
          {/* Column headers */}
          <div style={{ display: "grid", gridTemplateColumns: "180px 1fr 160px 180px",
                        gap: 16, padding: "0 19px", marginBottom: 6 }}>
            {["Reviewer", "Review", "Customer", "Discount & actions"].map(h => (
              <div key={h} style={{ fontSize: 11, fontWeight: 600, color: "#9ca3af", textTransform: "uppercase", letterSpacing: "0.05em" }}>
                {h}
              </div>
            ))}
          </div>
          {visible.map(r => <ReviewCard key={r.id} review={r} onRefresh={load} />)}
        </div>
      )}

      {showAdd && <AddReviewModal onSaved={() => { setShowAdd(false); load(); }} onClose={() => setShowAdd(false)} />}
    </div>
  );
}
