// ---- Secondary views: Favorites, Identity, Billing ----

function FavCard({ d, onBuy, onHandles, onFav, onIdentity, hasIdentity, handlesGenerated, onAvail, availChecked, isFav = true }) {
  const base = d.display.slice(0, d.display.length - d.ext.length);
  // Use the genuine cached check result (from a prior valuation lookup) — never
  // fabricated data. The rich preview only shows when a real result exists.
  const cached = window.getHandleCache ? window.getHandleCache(d.name) : null;
  const handles = (handlesGenerated && cached && Array.isArray(cached.list)) ? cached.list : null;
  const free = handles ? handles.filter(h => h.available === true).length : 0;
  const total = handles ? handles.length : 14;
  return (
    <div className="fav-card">
      <div className="fav-card-top">
        <div className="fav-card-name">{base}<span className="domain-ext">{d.ext}</span></div>
        <button className={'fav-heart' + (isFav ? '' : ' fav-heart-add')} onClick={() => onFav(d)} title={isFav ? 'Remove from favorites' : 'Add to favorites'} aria-pressed={isFav}>
          {isFav ? (
            <svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true"><path fill="currentColor" d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"></path></svg>
          ) : (
            <svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true"><path fill="none" stroke="currentColor" strokeWidth="1.8" d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"></path></svg>
          )}
        </button>
      </div>
      <div className="fav-card-row">
        {d.available === false ? (
          <span className="badge-available badge-taken fav-card-badge">
            <span className="dot"></span>Taken
          </span>
        ) : d.available === true ? (
          <span className="badge-available fav-card-badge">
            <span className="dot"></span>Available
          </span>
        ) : availChecked ? (
          <span className="badge-available fav-card-badge fav-card-badge-unknown">
            <span className="dot"></span>Unknown
          </span>
        ) : (
          <button className="fav-avail-check" onClick={() => onAvail(d)} title="Check domain availability">
            <span className="fav-avail-q" aria-hidden="true">?</span>Check availability
          </button>
        )}
        {typeof d.price === 'number' ? (
          <span className="fav-card-price">${d.price.toFixed(2)}<span className="per">/yr</span></span>
        ) : null}
      </div>
      {handles ? (
        <button className="handle-pill" onClick={() => onHandles(d)} title="View handle availability">
          <span className="hc-dots" aria-hidden="true">
            {handles.map(h => <span key={h.platform} className={'hc-dot ' + (h.available === true ? 'dot-free' : h.available === false ? 'dot-taken' : 'dot-unknown')}></span>)}
          </span>
          <span className="hc-label">{free}/{total} handles free</span>
          <span className="hc-chev" aria-hidden="true">›</span>
        </button>
      ) : (
        <button className="handle-pill handle-pill-empty" onClick={() => onHandles(d)} title="Check social handles">
          <span className="hc-at" aria-hidden="true">@</span>
          <span className="hc-label">Check social handles</span>
          <span className="hc-chev" aria-hidden="true">›</span>
        </button>
      )}
      <div className="fav-card-actions">
        <button className="fav-act fav-act-handles" onClick={() => onHandles(d)}>
          <span className="fav-act-ico" aria-hidden="true">@</span>Handles
        </button>
        <button className="fav-act fav-act-buy" onClick={() => onBuy(d)}>Buy now</button>
      </div>
      <button className={'fav-identity' + (hasIdentity ? '' : ' fav-identity-locked')} onClick={() => onIdentity(d)}>
        <span className="fav-id-ico" aria-hidden="true">{hasIdentity ? '✦' : '⚿'}</span>
        Create identity{hasIdentity ? '' : ' · Pro'}
      </button>
    </div>
  );
}

const FAV_PAGE_SIZE = 12;

function FavoritesView({ favs, onBuy, onHandles, onFav, onIdentity, hasIdentity, handlesDoneIds, onAvail, availDoneIds }) {
  const [extFilter, setExtFilter] = React.useState('all');
  const [availFilter, setAvailFilter] = React.useState('all');
  const [handleFilter, setHandleFilter] = React.useState('all');
  const [ratingFilter, setRatingFilter] = React.useState('all');
  const [page, setPage] = React.useState(1);

  const list = favs || [];
  const handlesSet = new Set(handlesDoneIds || []);
  const availSet = new Set(availDoneIds || []);

  // 'available' | 'taken' | 'unknown' (checked, inconclusive) | 'unchecked'
  const availStatus = (d) => d.available === true ? 'available'
    : d.available === false ? 'taken'
    : availSet.has(d.id) ? 'unknown' : 'unchecked';
  // 'checked' only when a real cached handle result exists for an explicitly-run check
  const handleStatus = (d) => {
    if (!handlesSet.has(d.id)) return 'unchecked';
    const c = window.getHandleCache ? window.getHandleCache(d.name) : null;
    return (c && Array.isArray(c.list)) ? 'checked' : 'unchecked';
  };
  const ratingOf = (d) => (d.review && typeof d.review.score === 'number') ? d.review.score : null;

  // Newest saved first. Favs without a save time (legacy rows) sink to the bottom
  // while keeping their relative order (sort is stable).
  const sorted = list.slice().sort((a, b) => (b.addedAt || 0) - (a.addedAt || 0));
  const exts = Array.from(new Set(list.map(d => d.ext))).sort();

  const filtered = sorted.filter(d => {
    if (extFilter !== 'all' && d.ext !== extFilter) return false;
    if (availFilter !== 'all' && availStatus(d) !== availFilter) return false;
    if (handleFilter !== 'all' && handleStatus(d) !== handleFilter) return false;
    if (ratingFilter !== 'all') {
      const r = ratingOf(d);
      if (ratingFilter === 'unrated') { if (r !== null) return false; }
      else if (r === null) return false;
      else if (ratingFilter === 'high' && r < 8) return false;
      else if (ratingFilter === 'mid' && (r < 6 || r >= 8)) return false;
      else if (ratingFilter === 'low' && r >= 6) return false;
    }
    return true;
  });

  const anyFilter = extFilter !== 'all' || availFilter !== 'all' || handleFilter !== 'all' || ratingFilter !== 'all';
  // Reset to the first page on any filter change. Done in the handlers (during
  // the change event) rather than in an effect, so it can't race the clamp
  // effect below when a filter both changes the page AND shrinks totalPages.
  const onFilterChange = (setter) => (e) => { setter(e.target.value); setPage(1); };
  const clearFilters = () => { setExtFilter('all'); setAvailFilter('all'); setHandleFilter('all'); setRatingFilter('all'); setPage(1); };

  const totalPages = Math.max(1, Math.ceil(filtered.length / FAV_PAGE_SIZE));
  const safePage = Math.min(page, totalPages);
  // Defensive clamp for non-filter shrink events (e.g. un-favoriting while on a
  // later page). Filter changes already reset to page 1 in their handlers.
  React.useEffect(() => { if (page !== safePage) setPage(safePage); }, [safePage, page]);
  const startIdx = (safePage - 1) * FAV_PAGE_SIZE;
  const pageItems = filtered.slice(startIdx, startIdx + FAV_PAGE_SIZE);
  const showingFrom = filtered.length ? startIdx + 1 : 0;
  const showingTo = Math.min(startIdx + FAV_PAGE_SIZE, filtered.length);

  return (
    <div className="view view-wide">
      <h1 className="view-title">Favorites</h1>
      <p className="view-sub">{list.length ? list.length + ' domain' + (list.length > 1 ? 's' : '') + " you've saved across searches." : "Domains you've saved across searches."}</p>
      {list.length === 0 ? (
        <div className="empty">
          <div className="empty-glyph">♡</div>
          <p>No favorites yet. Tap the heart on any result to save it here.</p>
        </div>
      ) : (
        <React.Fragment>
          <div className="fav-filters">
            <select className="fav-filter" value={extFilter} onChange={onFilterChange(setExtFilter)} aria-label="Filter by extension">
              <option value="all">All extensions</option>
              {exts.map(x => <option key={x} value={x}>{x}</option>)}
            </select>
            <select className="fav-filter" value={availFilter} onChange={onFilterChange(setAvailFilter)} aria-label="Filter by availability">
              <option value="all">Any availability</option>
              <option value="available">Available</option>
              <option value="taken">Taken</option>
              <option value="unknown">Checked · unknown</option>
              <option value="unchecked">Not checked</option>
            </select>
            <select className="fav-filter" value={handleFilter} onChange={onFilterChange(setHandleFilter)} aria-label="Filter by social handles">
              <option value="all">Any handles</option>
              <option value="checked">Handles checked</option>
              <option value="unchecked">Handles not checked</option>
            </select>
            <select className="fav-filter" value={ratingFilter} onChange={onFilterChange(setRatingFilter)} aria-label="Filter by rating">
              <option value="all">Any rating</option>
              <option value="high">8+ rating</option>
              <option value="mid">6–7.9 rating</option>
              <option value="low">Below 6</option>
              <option value="unrated">Unrated</option>
            </select>
            {anyFilter ? <button className="fav-filter-clear" onClick={clearFilters}>Clear</button> : null}
            <span className="fav-filter-count">{filtered.length} of {list.length}</span>
          </div>
          {filtered.length === 0 ? (
            <div className="empty">
              <div className="empty-glyph">⌕</div>
              <p>No favorites match these filters.</p>
              <button className="fav-filter-clear" onClick={clearFilters}>Clear filters</button>
            </div>
          ) : (
            <React.Fragment>
              <div className="fav-grid">
                {pageItems.map((d) => (
                  <FavCard key={d.id} d={d} onBuy={onBuy} onHandles={onHandles} onFav={onFav} onIdentity={onIdentity} hasIdentity={hasIdentity} handlesGenerated={handlesSet.has(d.id)} onAvail={onAvail} availChecked={availSet.has(d.id)} />
                ))}
              </div>
              {totalPages > 1 ? (
                <div className="pager">
                  <span className="pager-info">Showing {showingFrom}–{showingTo} of {filtered.length}</span>
                  <div className="pager-ctrls">
                    <button className="pager-btn" disabled={safePage <= 1} onClick={() => setPage(safePage - 1)} aria-label="Previous page">‹</button>
                    {pageWindow(safePage, totalPages).map((p, i) => (
                      p === '…'
                        ? <span key={'e' + i} className="pager-gap">…</span>
                        : <button key={p} className={'pager-num' + (p === safePage ? ' pager-num-on' : '')} onClick={() => setPage(p)} aria-current={p === safePage ? 'page' : undefined}>{p}</button>
                    ))}
                    <button className="pager-btn" disabled={safePage >= totalPages} onClick={() => setPage(safePage + 1)} aria-label="Next page">›</button>
                  </div>
                </div>
              ) : null}
            </React.Fragment>
          )}
        </React.Fragment>
      )}
    </div>
  );
}

function HistoryRow({ d, onBuy, onHandles, onFav, onIdentity, hasIdentity, handlesGenerated, onAvail, availChecked }) {
  const base = d.display.slice(0, d.display.length - d.ext.length);
  const cached = window.getHandleCache ? window.getHandleCache(d.name) : null;
  const handles = (handlesGenerated && cached && Array.isArray(cached.list)) ? cached.list : null;
  const free = handles ? handles.filter(h => h.available === true).length : 0;
  const total = handles ? handles.length : 14;
  return (
    <div className="hist-row">
      <div className="hist-row-name">{base}<span className="domain-ext">{d.ext}</span></div>
      <div className="hist-row-status">
        {d.available === false ? (
          <span className="badge-available badge-taken"><span className="dot"></span>Taken</span>
        ) : d.available === true ? (
          <span className="badge-available"><span className="dot"></span>Available</span>
        ) : availChecked ? (
          <span className="badge-available fav-card-badge-unknown"><span className="dot"></span>Unknown</span>
        ) : (
          <button className="fav-avail-check" onClick={() => onAvail(d)} title="Check domain availability">
            <span className="fav-avail-q" aria-hidden="true">?</span>Check availability
          </button>
        )}
      </div>
      <div className="hist-row-price">
        {typeof d.price === 'number' ? (
          <span className="fav-card-price">${d.price.toFixed(2)}<span className="per">/yr</span></span>
        ) : null}
      </div>
      <div className="hist-row-actions">
        <button className="hist-act" onClick={() => onHandles(d)} title="Social handle availability">
          <span className="fav-act-ico" aria-hidden="true">@</span>
          <span className="hist-act-lbl">{handles ? free + '/' + total : 'Handles'}</span>
        </button>
        <button className={'hist-act hist-act-id' + (hasIdentity ? '' : ' hist-act-locked')} onClick={() => onIdentity(d)} title={hasIdentity ? 'Create brand identity' : 'Create identity · Pro'}>
          <span className="hist-act-ico" aria-hidden="true">{hasIdentity ? '✦' : '⚿'}</span>
          <span className="hist-act-lbl">Identity</span>
        </button>
        <button className="hist-act hist-act-buy" onClick={() => onBuy(d)}>Buy now</button>
        <button className="fav-heart fav-heart-add hist-heart" onClick={() => onFav(d)} title="Add to favorites" aria-pressed="false">
          <svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true"><path fill="none" stroke="currentColor" strokeWidth="1.8" d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"></path></svg>
        </button>
      </div>
    </div>
  );
}

function pageWindow(current, total) {
  // Compact, windowed page list with ellipsis markers ('…') for large counts.
  if (total <= 7) return Array.from({ length: total }, (_, i) => i + 1);
  const out = [1];
  let start = Math.max(2, current - 1);
  let end = Math.min(total - 1, current + 1);
  if (current <= 3) { start = 2; end = 4; }
  if (current >= total - 2) { start = total - 3; end = total - 1; }
  if (start > 2) out.push('…');
  for (let i = start; i <= end; i++) out.push(i);
  if (end < total - 1) out.push('…');
  out.push(total);
  return out;
}

const HISTORY_PAGE_SIZE = 12;

function HistoryUpgrade({ onUpgrade }) {
  return (
    <div className="view">
      <h1 className="view-title">History</h1>
      <p className="view-sub">Every domain you've generated, kept in one place.</p>
      <div className="lock-card">
        <div className="lock-badge">Pro feature</div>
        <div className="lock-glyph" aria-hidden="true">⚿</div>
        <h2 className="lock-title">Unlock your full search history</h2>
        <p className="lock-text">Pro keeps every name you generate in one place, so you can revisit, compare and buy them later — with live availability, social handles and registrar prices. Upgrade to Pro to open your history.</p>
        <button className="btn-primary" onClick={onUpgrade}>Upgrade to Pro</button>
      </div>
    </div>
  );
}

function HistoryView({ history, favIds, onBuy, onHandles, onFav, onIdentity, hasIdentity, handlesDoneIds, onAvail, availDoneIds, onUpgrade }) {
  // Search history is a Pro feature — free-plan users get an upgrade prompt
  // instead of the full list. (hasIdentity is true only on the Pro plan.)
  // Kept above all hooks so the hook order stays stable across plan changes.
  if (!hasIdentity) return <HistoryUpgrade onUpgrade={onUpgrade} />;

  // Everything the user has generated that isn't already a favorite. Rows carry
  // the same right-side-panel actions (handles / availability / buy) as favorites,
  // in a compact list that paginates so a long history stays scannable.
  const favSet = new Set(favIds || []);
  const items = (history || []).filter(d => !favSet.has(d.id));
  const [page, setPage] = React.useState(1);

  const totalPages = Math.max(1, Math.ceil(items.length / HISTORY_PAGE_SIZE));
  const safePage = Math.min(page, totalPages);
  React.useEffect(() => { if (page !== safePage) setPage(safePage); }, [safePage, page]);

  const startIdx = (safePage - 1) * HISTORY_PAGE_SIZE;
  const pageItems = items.slice(startIdx, startIdx + HISTORY_PAGE_SIZE);
  const showingFrom = items.length ? startIdx + 1 : 0;
  const showingTo = Math.min(startIdx + HISTORY_PAGE_SIZE, items.length);

  return (
    <div className="view view-wide">
      <h1 className="view-title">History</h1>
      <p className="view-sub">{items.length ? items.length + ' domain' + (items.length > 1 ? 's' : '') + " you've generated and not yet saved." : "Domains you've generated across searches."}</p>
      {items.length === 0 ? (
        <div className="empty">
          <div className="empty-glyph">◷</div>
          <p>No history yet. Generate some names — the ones you don't favorite collect here.</p>
        </div>
      ) : (
        <React.Fragment>
          <div className="hist-list">
            {pageItems.map((d) => (
              <HistoryRow key={d.id} d={d} onBuy={onBuy} onHandles={onHandles} onFav={onFav} onIdentity={onIdentity} hasIdentity={hasIdentity} handlesGenerated={(handlesDoneIds || []).includes(d.id)} onAvail={onAvail} availChecked={(availDoneIds || []).includes(d.id)} />
            ))}
          </div>
          {totalPages > 1 ? (
            <div className="pager">
              <span className="pager-info">Showing {showingFrom}–{showingTo} of {items.length}</span>
              <div className="pager-ctrls">
                <button className="pager-btn" disabled={safePage <= 1} onClick={() => setPage(safePage - 1)} aria-label="Previous page">‹</button>
                {pageWindow(safePage, totalPages).map((p, i) => (
                  p === '…'
                    ? <span key={'e' + i} className="pager-gap">…</span>
                    : <button key={p} className={'pager-num' + (p === safePage ? ' pager-num-on' : '')} onClick={() => setPage(p)} aria-current={p === safePage ? 'page' : undefined}>{p}</button>
                ))}
                <button className="pager-btn" disabled={safePage >= totalPages} onClick={() => setPage(safePage + 1)} aria-label="Next page">›</button>
              </div>
            </div>
          ) : null}
        </React.Fragment>
      )}
    </div>
  );
}

// IdentityView now lives in identity.jsx (full brand-identity generator).



function BillingView({ creditsUsed, creditsTotal, extra, allotment, plan, plans, catalog, signedIn, busy, pending, notice, subscription, onCancel, onResume, onClaimOffer, onCheckout, onManage, onSignIn }) {
  const [yearly, setYearly] = React.useState(false);
  const usedShown = Math.min(creditsUsed, creditsTotal);
  const pct = creditsTotal > 0 ? Math.min(100, Math.round((usedShown / creditsTotal) * 100)) : 0;
  const left = Math.max(0, creditsTotal - creditsUsed);

  // ---- Subscription self-management (cancel / resume / retention offer) ----
  const sub = subscription || null;
  const REASONS = [
    { v: 'too_expensive', t: 'Too expensive' },
    { v: 'missing_features', t: 'Missing features I need' },
    { v: 'switched_service', t: 'Found a better alternative' },
    { v: 'unused', t: "I'm not using it enough" },
    { v: 'too_complex', t: 'Too hard to use' },
    { v: 'low_quality', t: "Quality wasn't good enough" },
    { v: 'customer_service', t: 'Customer support issues' },
    { v: 'other', t: 'Other' },
  ];
  const fmtDate = (sec) => {
    if (!sec) return '';
    try { return new Date(sec * 1000).toLocaleDateString(undefined, { year: 'numeric', month: 'long', day: 'numeric' }); }
    catch (e) { return ''; }
  };
  const [modal, setModal] = React.useState(null); // 'reasons' | 'offer' | 'done' | 'claimed'
  const [reason, setReason] = React.useState('');
  const [comment, setComment] = React.useState('');
  const [working, setWorking] = React.useState(false);
  const [subErr, setSubErr] = React.useState(null);
  const openCancel = () => { setReason(''); setComment(''); setSubErr(null); setModal('reasons'); };
  const closeModal = () => { if (!working) setModal(null); };
  const continueCancel = () => {
    if (!reason) return;
    if (sub && sub.retentionOfferAvailable) { setModal('offer'); return; }
    doCancel();
  };
  const doCancel = async () => {
    setWorking(true); setSubErr(null);
    try { await onCancel(reason, comment); setModal('done'); }
    catch (e) { setSubErr('Something went wrong — please try again.'); }
    finally { setWorking(false); }
  };
  const doClaim = async () => {
    setWorking(true); setSubErr(null);
    try { await onClaimOffer(); setModal('claimed'); }
    catch (e) { setSubErr('Something went wrong — please try again.'); }
    finally { setWorking(false); }
  };
  const doResume = async () => {
    setWorking(true); setSubErr(null);
    try { await onResume(); }
    catch (e) { /* state unchanged on failure */ }
    finally { setWorking(false); }
  };

  // Format a Stripe amount (in cents) as a price string.
  const fmt = (cents, currency) => {
    if (cents == null) return '—';
    const v = cents / 100;
    const usd = (currency || 'usd').toLowerCase() === 'usd';
    const s = Number.isInteger(v) ? String(v) : v.toFixed(2);
    return usd ? '$' + s : s + ' ' + (currency || '').toUpperCase();
  };
  const cadence = (i) => (i === 'year' ? 'yr' : i === 'month' ? 'mo' : '');

  const subs = (catalog && Array.isArray(catalog.subscriptions)) ? catalog.subscriptions : [];
  const packsLive = (catalog && Array.isArray(catalog.creditPacks)) ? catalog.creditPacks : [];
  const hasSubs = subs.length > 0;
  const hasPacks = packsLive.length > 0;

  // Group subscription prices by product so monthly + yearly render as one card.
  const subGroups = [];
  const byProduct = {};
  for (const s of subs) {
    if (!byProduct[s.productId]) { byProduct[s.productId] = { product: s, prices: [] }; subGroups.push(byProduct[s.productId]); }
    byProduct[s.productId].prices.push(s);
  }
  const subGroup = subGroups[0] || null;
  const subMonthly = subGroup ? subGroup.prices.find(x => x.interval === 'month') : null;
  const subYearly = subGroup ? subGroup.prices.find(x => x.interval === 'year') : null;
  const hasBothIntervals = !!(subMonthly && subYearly);
  // Both amounts must be finite positive cents before we claim any savings, and
  // clamp to a sane range so a malformed catalog can never show a misleading %.
  const _monCents = subMonthly && subMonthly.unitAmount > 0 ? subMonthly.unitAmount : 0;
  const _yrCents = subYearly && subYearly.unitAmount > 0 ? subYearly.unitAmount : 0;
  const yearSavePct = (hasBothIntervals && _monCents && _yrCents)
    ? Math.max(0, Math.min(99, Math.round((1 - _yrCents / (_monCents * 12)) * 100))) : 0;
  // The credit pack priced the same as the monthly plan, used to highlight the
  // bonus credits a subscriber gets for the same money.
  const samePricePack = (subMonthly && packsLive.length)
    ? packsLive.find(pk => pk.unitAmount === subMonthly.unitAmount) : null;

  const bannerStyle = (ok) => ({
    padding: '10px 14px', borderRadius: 10, marginBottom: 14, fontSize: 14,
    background: ok ? 'rgba(34,197,94,0.12)' : 'rgba(245,158,11,0.14)',
    color: ok ? '#15803d' : '#b45309',
    border: '1px solid ' + (ok ? 'rgba(34,197,94,0.3)' : 'rgba(245,158,11,0.35)'),
  });

  return (
    <div className="view view-wide">
      <h1 className="view-title">Billing</h1>
      <p className="view-sub">Your plan, credit balance and top-ups.</p>

      {notice === 'success' ? (
        <div style={bannerStyle(true)}>Payment received — your balance updates in a moment.</div>
      ) : null}
      {notice === 'cancel' ? (
        <div style={bannerStyle(false)}>Checkout canceled — no charge was made.</div>
      ) : null}

      <div className="bill-card">
        <div className="bill-row">
          <div>
            <div className="bill-label">Current balance</div>
            <div className="bill-value">{left} credits left</div>
            <div className="bill-note">On the {plans[plan].name} plan · {allotment} monthly{extra > 0 ? ' + ' + extra + ' extra' : ''}</div>
          </div>
          {signedIn && plan === 'pro' ? (
            <div className="bill-actions">
              <button className={'btn-ghost btn-sm' + (pending === 'manage' ? ' is-loading' : '')} onClick={onManage} disabled={busy}>
                {pending === 'manage' ? <React.Fragment><span className="btn-spin" aria-hidden="true"></span>Opening…</React.Fragment> : 'Manage subscription'}
              </button>
              {sub && sub.cancelAtPeriodEnd ? (
                <button className="btn-ghost btn-sm" onClick={doResume} disabled={busy || working}>{working ? 'Working…' : 'Resume subscription'}</button>
              ) : (
                <button type="button" className="bill-cancel-link" onClick={openCancel} disabled={busy}>Cancel subscription</button>
              )}
            </div>
          ) : null}
        </div>
        {signedIn && plan === 'pro' && sub ? (
          sub.cancelAtPeriodEnd ? (
            <div className="bill-status bill-status-warn">Your Pro plan ends on {fmtDate(sub.currentPeriodEnd)}. You'll keep your {extra} extra credits — only the monthly Pro credits stop renewing.</div>
          ) : sub.currentPeriodEnd ? (
            <div className="bill-status">Renews on {fmtDate(sub.currentPeriodEnd)}{sub.discountActive ? ' · 50% off applied to your next invoice' : ''}</div>
          ) : null
        ) : null}
        <div className="bill-usage">
          <div className="credit-bar"><div className="credit-fill" style={{ width: pct + '%' }}></div></div>
          <div className="bill-note bill-usage-foot">
            <span>{usedShown} of {creditsTotal} credits used</span>
          </div>
        </div>
      </div>

      <h2 className="view-h2">Plans</h2>
      {hasBothIntervals && plan !== 'pro' ? (
        <div className="cad-toggle" role="group" aria-label="Billing period">
          <button type="button" className={'cad-opt' + (!yearly ? ' cad-on' : '')} onClick={() => setYearly(false)}>Monthly</button>
          <button type="button" className={'cad-opt' + (yearly ? ' cad-on' : '')} onClick={() => setYearly(true)}>Yearly{yearSavePct > 0 ? <span className="cad-save">Save {yearSavePct}%</span> : null}</button>
        </div>
      ) : null}
      <div className="plan-grid">
        <div className={'plan-card' + (plan === 'free' ? ' plan-current' : '')}>
          <div className="plan-top">
            <span className="plan-name">Free</span>
            {plan === 'free' ? <span className="tag plan-curtag">Current</span> : null}
          </div>
          <div className="plan-price">$0<span className="plan-cadence">/forever</span></div>
          <p className="plan-blurb">Start finding names right away.</p>
          <ul className="plan-feats">
            <li className="feat-ok"><span className="feat-mark" aria-hidden="true">✓</span>{plans.free.credits} credits / month</li>
            <li className="feat-ok"><span className="feat-mark" aria-hidden="true">✓</span>Generate name ideas & availability</li>
            <li className="feat-ok"><span className="feat-mark" aria-hidden="true">✓</span>Handles, WHOIS & price comparison</li>
            <li className="feat-no"><span className="feat-mark" aria-hidden="true">✕</span>Create brand name identity</li>
            <li className="feat-ok"><span className="feat-mark" aria-hidden="true">✓</span>Buy extra credits anytime</li>
          </ul>
          <button className="btn-ghost btn-sm plan-btn" disabled>{plan === 'free' ? 'Current plan' : 'Free plan'}</button>
        </div>

        {hasSubs && subGroup ? (() => {
          const p = subGroup.product;
          const current = plan === 'pro';
          const selected = (yearly && subYearly) ? subYearly : (subMonthly || subYearly || subGroup.prices[0]);
          const isYr = selected.interval === 'year';
          const saveAmt = hasBothIntervals ? (subMonthly.unitAmount * 12 - subYearly.unitAmount) / 100 : 0;
          const bonusVsPack = (samePricePack && samePricePack.credits && p.credits) ? p.credits - samePricePack.credits : 0;
          return (
            <div className={'plan-card plan-card-pro' + (current ? ' plan-current' : '')} key={p.productId}>
              <div className="plan-top">
                <span className="plan-name">{p.productName}</span>
                {current ? <span className="tag plan-curtag">Current</span> : <span className="tag tag-best">Recommended</span>}
              </div>
              <div className="plan-price">{fmt(selected.unitAmount, selected.currency)}<span className="plan-cadence">/{cadence(selected.interval) || 'mo'}</span></div>
              {isYr && yearSavePct > 0 ? <div className="plan-save-line">Save {yearSavePct}%{saveAmt > 0 ? ' · $' + saveAmt.toFixed(0) + '/yr off' : ''}</div> : null}
              <p className="plan-blurb">{p.description || 'For founders shipping a brand.'}</p>
              <ul className="plan-feats">
                {p.credits ? <li className="feat-ok feat-hl"><span className="feat-mark" aria-hidden="true">✓</span>{p.credits.toLocaleString()} credits / month</li> : null}
                <li className="feat-ok"><span className="feat-mark" aria-hidden="true">✓</span>Everything in Free</li>
                <li className="feat-ok"><span className="feat-mark" aria-hidden="true">✓</span>Create brand identity</li>
                <li className="feat-ok"><span className="feat-mark" aria-hidden="true">✓</span>Domain valuation & evaluation</li>
                <li className="feat-ok"><span className="feat-mark" aria-hidden="true">✓</span>Domain Hunt for undervalued names</li>
                <li className="feat-ok"><span className="feat-mark" aria-hidden="true">✓</span>Domain search history</li>
              </ul>
              {bonusVsPack > 0 ? (
                <div className="plan-bonus">{bonusVsPack.toLocaleString()} more credits than the {fmt(samePricePack.unitAmount, samePricePack.currency)} pack — best value</div>
              ) : null}
              {current ? (
                <button className={'btn-ghost btn-sm plan-btn' + (pending === 'manage' ? ' is-loading' : '')} onClick={onManage} disabled={busy}>
                  {pending === 'manage' ? <React.Fragment><span className="btn-spin" aria-hidden="true"></span>Opening…</React.Fragment> : 'Manage subscription'}
                </button>
              ) : (
                <button className={'btn-primary plan-btn' + (pending === selected.priceId ? ' is-loading' : '')} onClick={() => onCheckout(selected.priceId)} disabled={busy}>
                  {pending === selected.priceId ? <React.Fragment><span className="btn-spin" aria-hidden="true"></span>Redirecting…</React.Fragment> : 'Get Pro · ' + fmt(selected.unitAmount, selected.currency) + '/' + (cadence(selected.interval) || 'mo')}
                </button>
              )}
            </div>
          );
        })() : (
          <div className="plan-card plan-card-pro">
            <div className="plan-top"><span className="plan-name">Pro</span><span className="tag tag-best">Recommended</span></div>
            <div className="plan-price">{plans.pro.price}<span className="plan-cadence">/mo</span></div>
            <p className="plan-blurb">For founders shipping a brand.</p>
            <ul className="plan-feats">
              <li className="feat-ok"><span className="feat-mark" aria-hidden="true">✓</span>{plans.pro.credits} credits / month</li>
              <li className="feat-ok"><span className="feat-mark" aria-hidden="true">✓</span>Everything in Free</li>
              <li className="feat-ok"><span className="feat-mark" aria-hidden="true">✓</span>Create brand identity & valuation</li>
              <li className="feat-ok"><span className="feat-mark" aria-hidden="true">✓</span>Domain Hunt for undervalued names</li>
              <li className="feat-ok"><span className="feat-mark" aria-hidden="true">✓</span>Domain search history</li>
            </ul>
            <button className="btn-primary plan-btn" onClick={() => { if (!signedIn) onSignIn(); }} disabled={signedIn}>
              {signedIn ? 'Currently unavailable' : 'Sign in to upgrade'}
            </button>
          </div>
        )}
      </div>

      <h2 className="view-h2" id="extra-credits">Buy extra credits</h2>
      <p className="view-mini">Available on any plan — top up whenever you run low. Credits never expire.</p>
      <div className="packs">
        {hasPacks ? packsLive.map((p, i) => {
          const rate = (p.credits && p.unitAmount) ? (p.unitAmount / 100) / p.credits : 0;
          const base = packsLive[0];
          const baseRate = (base.credits && base.unitAmount) ? (base.unitAmount / 100) / base.credits : 0;
          const save = (baseRate > 0 && rate > 0) ? Math.round((1 - rate / baseRate) * 100) : 0;
          const popular = i === 1;
          return (
            <div className={'pack' + (popular ? ' pack-popular' : '')} key={p.priceId}>
              {popular ? <span className="tag tag-best pack-tag">Popular</span> : null}
              <div className="pack-top">
                <span className="pack-coin" aria-hidden="true"></span>
                <span className="pack-credits">{(p.credits || 0).toLocaleString()}<span className="pack-credits-lbl">credits</span></span>
              </div>
              <div className="pack-price">{fmt(p.unitAmount, p.currency)}<span className="pack-rate">${rate.toFixed(3)}/credit</span></div>
              {save > 0 ? <span className="pack-save">Save {save}%</span> : <span className="pack-save pack-save-base">Standard rate</span>}
              <button className={'pack-buy ' + (popular ? 'btn-primary' : 'btn-ghost') + (pending === p.priceId ? ' is-loading' : '')} onClick={() => onCheckout(p.priceId)} disabled={busy}>{pending === p.priceId ? <React.Fragment><span className="btn-spin" aria-hidden="true"></span>Redirecting…</React.Fragment> : 'Buy ' + (p.credits || 0).toLocaleString() + ' credits'}</button>
            </div>
          );
        }) : [{ credits: 50 }, { credits: 150 }, { credits: 500 }].map((p, i) => (
          <div className={'pack' + (i === 1 ? ' pack-popular' : '')} key={p.credits}>
            {i === 1 ? <span className="tag tag-best pack-tag">Popular</span> : null}
            <div className="pack-top">
              <span className="pack-coin" aria-hidden="true"></span>
              <span className="pack-credits">{p.credits}<span className="pack-credits-lbl">credits</span></span>
            </div>
            <button className={'pack-buy ' + (i === 1 ? 'btn-primary' : 'btn-ghost')} onClick={() => { if (!signedIn) onSignIn(); }} disabled={signedIn}>
              {signedIn ? 'Currently unavailable' : 'Sign in to buy'}
            </button>
          </div>
        ))}
      </div>

      {modal ? (
        <div className="modal-scrim" onClick={closeModal}>
          <div className="modal-card" onClick={(e) => e.stopPropagation()}>
            {modal === 'reasons' ? (
              <React.Fragment>
                <div className="modal-title">Cancel your subscription?</div>
                <p className="modal-text">Your Pro plan stays active until{sub && sub.currentPeriodEnd ? ' ' + fmtDate(sub.currentPeriodEnd) : ' the end of your billing period'}, and you won't be charged again. You'll keep any extra credits you've purchased — only the monthly Pro credits stop renewing.</p>
                <div className="cancel-reasons">
                  {REASONS.map(r => (
                    <label key={r.v} className={'reason-opt' + (reason === r.v ? ' reason-on' : '')}>
                      <input type="radio" name="cancel-reason" value={r.v} checked={reason === r.v} onChange={() => setReason(r.v)} />
                      <span>{r.t}</span>
                    </label>
                  ))}
                </div>
                <textarea className="cancel-comment" placeholder="Anything else you'd like to share? (optional)" value={comment} onChange={(e) => setComment(e.target.value)} maxLength={500}></textarea>
                {subErr ? <div className="cancel-err">{subErr}</div> : null}
                <div className="modal-actions">
                  <button className="btn-ghost btn-sm" onClick={closeModal} disabled={working}>Never mind</button>
                  <button className="btn-primary btn-sm" onClick={continueCancel} disabled={!reason || working}>{working ? 'Working…' : 'Continue'}</button>
                </div>
              </React.Fragment>
            ) : null}
            {modal === 'offer' ? (
              <React.Fragment>
                <div className="modal-title">Wait — here's 50% off your next month</div>
                <p className="modal-text">Stay on Pro and your next renewal is <strong>half price</strong>, one time only. After that it renews at the normal price, and you can still cancel anytime.</p>
                {subErr ? <div className="cancel-err">{subErr}</div> : null}
                <div className="modal-actions">
                  <button className="btn-ghost btn-sm" onClick={doCancel} disabled={working}>No thanks, cancel</button>
                  <button className="btn-primary btn-sm" onClick={doClaim} disabled={working}>{working ? 'Applying…' : 'Claim 50% off & stay'}</button>
                </div>
              </React.Fragment>
            ) : null}
            {modal === 'done' ? (
              <React.Fragment>
                <div className="modal-title">Your subscription is canceled</div>
                <p className="modal-text">Pro stays active until{sub && sub.currentPeriodEnd ? ' ' + fmtDate(sub.currentPeriodEnd) : ' the end of your billing period'}. You won't be charged again, and your extra credits remain yours.</p>
                <div className="modal-actions">
                  <button className="btn-primary btn-sm" onClick={() => setModal(null)}>Done</button>
                </div>
              </React.Fragment>
            ) : null}
            {modal === 'claimed' ? (
              <React.Fragment>
                <div className="modal-title">You're all set — 50% off applied</div>
                <p className="modal-text">Your next invoice will be half price. After that, Pro renews at the normal price{sub && sub.currentPeriodEnd ? ' on ' + fmtDate(sub.currentPeriodEnd) : ''}.</p>
                <div className="modal-actions">
                  <button className="btn-primary btn-sm" onClick={() => setModal(null)}>Great</button>
                </div>
              </React.Fragment>
            ) : null}
          </div>
        </div>
      ) : null}
    </div>
  );
}

function ProfileView({ user, isSignedIn, onSignIn, onSignUp, onSignOut, onManage }) {
  if (!isSignedIn) {
    return (
      <div className="view">
        <h1 className="view-title">Profile</h1>
        <p className="view-sub">Sign in to save your domains, favorites and brand identities.</p>
        <div className="pf-card">
          <div className="pf-card-h">You're browsing as a guest</div>
          <p className="view-mini" style={{ margin: '0 0 16px' }}>
            Create a free account to keep your work in sync across devices. Your favorites,
            generated names and brand kits are saved to your account.
          </p>
          <div className="pf-actions">
            <button className="btn-primary btn-sm" onClick={onSignUp}>Create account</button>
            <button className="btn-ghost btn-sm" onClick={onSignIn}>Sign in</button>
          </div>
        </div>
      </div>
    );
  }

  const name = (user && user.name) || 'Account';
  const email = (user && user.email) || '';
  return (
    <div className="view">
      <h1 className="view-title">Profile</h1>
      <p className="view-sub">Manage your account details and security.</p>

      <div className="pf-id">
        <span className="pf-avatar" style={user && user.imageUrl ? { backgroundImage: 'url(' + user.imageUrl + ')', backgroundSize: 'cover', backgroundPosition: 'center', color: 'transparent' } : null}>
          {user && user.imageUrl ? '' : (name.trim().charAt(0).toUpperCase() || 'A')}
        </span>
        <div>
          <div className="pf-name">{name || '—'}</div>
          <div className="pf-email">{email || '—'}</div>
        </div>
      </div>

      <div className="pf-card">
        <div className="pf-card-h">Account</div>
        <p className="view-mini" style={{ margin: '0 0 16px' }}>
          Update your name, email, password and connected logins from your secure account settings.
        </p>
        <div className="pf-actions">
          <button className="btn-primary btn-sm" onClick={onManage}>Manage account</button>
        </div>
      </div>

      <div className="pf-card pf-danger">
        <div className="pf-card-h">Sign out</div>
        <p className="view-mini" style={{ margin: '0 0 14px' }}>Sign out of namit on this device.</p>
        <button className="btn-ghost btn-sm" onClick={onSignOut}>Sign out</button>
      </div>
    </div>
  );
}

Object.assign(window, { FavoritesView, HistoryView, BillingView, ProfileView });
