// MagicRascals admin panel — Supabase-backed product CRUD + URL importer.
// Requires admin-config.js to have SUPABASE_URL + SUPABASE_ANON filled in,
// and the schema from /admin/schema.sql to have been run on the project.

const CATEGORY_OPTIONS = [
  'nursery','travel','feeding','developmental','wooden','stem','creative','outdoor','books','apparel'
];
const STAGE_OPTIONS = ['pre-baby','infant','toddler','kid'];
const LEARNING_OPTIONS = ['stem','creativity','motor','sensory','language','social-emotional'];
const STATUS_OPTIONS  = ['draft','published','archived'];

function emptyProduct() {
  return {
    name: '', brand: '', description: '', why: '', benefit: '',
    price: null, price_high: null, currency: 'USD',
    age_min: null, age_max: null,
    category: 'nursery', stage: 'pre-baby', learning: [],
    size: '', materials: '', made_in: '', how_to_use: '',
    image_url: '', gallery_urls: [],
    primary_retailer: '', primary_url: '', retailers: [],
    status: 'draft', featured: false, tags: [], notes: '',
    source_url: '', imported_via: 'manual',
  };
}

function AdminPage() {
  const [supaState, setSupaState] = useState(() => ({
    ready: !!(window.MR && window.MR.ready),
    ok: !!(window.MR && window.MR.supabase),
  }));
  const [session, setSession] = useState(null);
  const [authedAdmin, setAuthedAdmin] = useState(false);
  const [authChecked, setAuthChecked] = useState(false);
  const [magicEmail, setMagicEmail] = useState('');
  const [magicSent, setMagicSent] = useState(false);
  const [magicErr, setMagicErr] = useState('');

  const [tab, setTab] = useState('products');           // 'products' | 'submissions' | 'pro'

  // ── Pro access requests ─────────────────────────────────────────────
  // Loaded lazily when the tab is opened. Stored as a flat array of
  // { user_id, status, requested_at, reviewed_at, reviewer_email, note }.
  const [proRequests, setProRequests]       = useState([]);
  const [proLoading, setProLoading]         = useState(false);
  const [proFilter, setProFilter]           = useState('requested'); // 'requested' | 'approved' | 'denied' | 'all'
  const [proErr, setProErr]                 = useState('');
  const [proUserEmails, setProUserEmails]   = useState({}); // userId → email
  const refreshPro = async () => {
    if (!window.MR || !window.MR.pro) return;
    setProLoading(true); setProErr('');
    const res = await window.MR.pro.listAllRequests();
    if (res.ok) {
      setProRequests(res.requests || []);
      // Look up emails for each user_id via auth admin endpoint (best
      // effort — falls back to showing the id).
      try {
        const ids = (res.requests || []).map(r => r.user_id);
        if (ids.length && window.MR.nodes && typeof window.MR.nodes.resolveDisplayNames === 'function') {
          const names = await window.MR.nodes.resolveDisplayNames(ids);
          setProUserEmails(prev => ({ ...prev, ...names }));
        }
      } catch {}
    } else {
      setProErr(res.reason === 'table-missing'
        ? 'pro_users table not found. Create it using the SQL in data-pro.js.'
        : (res.reason || 'Could not load requests'));
    }
    setProLoading(false);
  };
  const setProStatus = async (userId, status) => {
    if (!window.MR.pro) return;
    const res = await window.MR.pro.setRequestStatus(userId, status);
    if (res.ok) {
      showToast(status === 'approved' ? 'Approved' : status === 'denied' ? 'Denied' : 'Updated');
      refreshPro();
    } else {
      showToast('Failed: ' + (res.reason || 'unknown'));
    }
  };
  const [products, setProducts] = useState([]);
  const [submissions, setSubmissions] = useState([]);
  const [submissionsLoading, setSubmissionsLoading] = useState(false);
  const [submissionFilter, setSubmissionFilter] = useState('pending'); // pending | approved | rejected | all
  const [loading, setLoading] = useState(false);
  const [editing, setEditing] = useState(null); // product object or null
  const [importerOpen, setImporterOpen] = useState(false);
  const [statusFilter, setStatusFilter] = useState('all');
  const [search, setSearch] = useState('');
  const [toast, setToast] = useState('');

  const showToast = (msg) => {
    setToast(msg);
    setTimeout(() => setToast(''), 2200);
  };

  // Wait for Supabase init.
  useEffect(() => {
    if (!window.MR) return;
    if (window.MR.ready) {
      setSupaState({ ready: true, ok: !!window.MR.supabase });
    } else {
      window.MR.readyPromise.then((r) => {
        setSupaState({ ready: true, ok: !!window.MR.supabase });
      });
    }
  }, []);

  // Watch auth state.
  useEffect(() => {
    if (!supaState.ok || !window.MR.supabase) return;
    const sb = window.MR.supabase;
    let mounted = true;
    sb.auth.getSession().then(({ data }) => {
      if (!mounted) return;
      setSession(data.session || null);
      setAuthChecked(true);
    });
    const { data: sub } = sb.auth.onAuthStateChange((_evt, sess) => {
      setSession(sess || null);
    });
    return () => { mounted = false; sub.subscription.unsubscribe(); };
  }, [supaState.ok]);

  // Verify the signed-in email is on the admin allowlist.
  const [adminCheckErr, setAdminCheckErr] = useState('');
  useEffect(() => {
    if (!session || !window.MR.supabase) { setAuthedAdmin(false); return; }
    const email = session.user && session.user.email;
    if (!email) { setAuthedAdmin(false); return; }
    setAdminCheckErr('');
    window.MR.supabase
      .from('admin_users')
      .select('email')
      .eq('email', email)
      .maybeSingle()
      .then(({ data, error }) => {
        if (error) {
          setAdminCheckErr(error.message || String(error));
          setAuthedAdmin(false);
        } else {
          setAuthedAdmin(!!data);
        }
      });
  }, [session]);

  // Load products when authed.
  const refresh = async () => {
    if (!window.MR.supabase || !authedAdmin) return;
    setLoading(true);
    let q = window.MR.supabase.from('products').select('*').order('updated_at', { ascending: false }).limit(200);
    if (statusFilter !== 'all') q = q.eq('status', statusFilter);
    if (search.trim()) q = q.or(`name.ilike.%${search.trim()}%,brand.ilike.%${search.trim()}%`);
    const { data, error } = await q;
    if (error) showToast('Load failed: ' + error.message);
    setProducts(data || []);
    setLoading(false);
  };
  useEffect(() => { if (authedAdmin) refresh(); /* eslint-disable-line */ }, [authedAdmin, statusFilter]);

  // Load product submissions (user-pasted URLs that didn't match the catalog).
  const refreshSubmissions = async () => {
    if (!window.MR.supabase || !authedAdmin) return;
    setSubmissionsLoading(true);
    let q = window.MR.supabase.from('product_submissions')
      .select('*')
      .order('created_at', { ascending: false })
      .limit(200);
    if (submissionFilter !== 'all') q = q.eq('status', submissionFilter);
    const { data, error } = await q;
    if (error) showToast('Submissions load failed: ' + error.message);
    setSubmissions(data || []);
    setSubmissionsLoading(false);
  };
  useEffect(() => {
    if (authedAdmin && tab === 'submissions') refreshSubmissions();
    if (authedAdmin && tab === 'pro') refreshPro();
    /* eslint-disable-line */
  }, [authedAdmin, tab, submissionFilter]);

  // Promote a submission → seed a draft product row from its extracted data.
  // Admin lands in the edit modal so they can tidy and publish.
  const promoteSubmission = async (sub) => {
    if (!window.MR.supabase) return;
    const e = sub.extracted || {};
    const draft = {
      ...emptyProduct(),
      name: e.title || '',
      brand: e.brand || '',
      description: e.description || '',
      price: e.price != null ? Number(e.price) : null,
      currency: e.currency || 'USD',
      image_url: e.image || '',
      gallery_urls: Array.isArray(e.gallery) ? e.gallery : [],
      source_url: sub.source_url,
      imported_via: 'user-submission',
      status: 'draft',
    };
    // Open the existing product editor with this draft pre-filled. On save
    // (handled by the editor), update the submission to 'approved' and
    // store the new product id.
    setEditing({ ...draft, _fromSubmissionId: sub.id });
  };

  const rejectSubmission = async (sub) => {
    if (!window.MR.supabase) return;
    const { error } = await window.MR.supabase
      .from('product_submissions')
      .update({ status: 'rejected' })
      .eq('id', sub.id);
    if (error) { showToast('Reject failed: ' + error.message); return; }
    showToast('Marked rejected');
    refreshSubmissions();
  };

  const sendMagic = async (e) => {
    e.preventDefault();
    setMagicErr('');
    if (!magicEmail.trim()) { setMagicErr('Enter your email'); return; }
    const { error } = await window.MR.supabase.auth.signInWithOtp({
      email: magicEmail.trim(),
      options: { emailRedirectTo: window.location.origin + window.location.pathname + '#admin' },
    });
    if (error) setMagicErr(error.message);
    else setMagicSent(true);
  };
  const signOut = async () => {
    await window.MR.supabase.auth.signOut();
    setSession(null);
  };

  // ─── Render: setup screen ───
  if (supaState.ready && !supaState.ok) {
    return <AdminSetupGate />;
  }
  if (!supaState.ready) {
    return <div className="page admin-page"><p className="admin-loading">Loading admin…</p></div>;
  }

  // ─── Render: auth gate ───
  if (!session || !authedAdmin) {
    return (
      <div className="page admin-page">
        <div className="admin-auth-card">
          <div className="page-eyebrow">Admin</div>
          <h1 className="page-title">Sign in.</h1>
          {!session && (
            <>
              <p className="admin-sub">We'll email you a magic link. Only allow-listed admin emails can edit products.</p>
              {magicSent ? (
                <div className="admin-auth-success">
                  <strong>Check your inbox.</strong>
                  <p>Click the link to come back signed in.</p>
                </div>
              ) : (
                <form className="admin-auth-form" onSubmit={sendMagic}>
                  <input type="email" required autoFocus className="gift-input" placeholder="you@magicrascals.com" value={magicEmail} onChange={(e) => setMagicEmail(e.target.value)} />
                  <button type="submit" className="btn" style={{ width: 'auto', padding: '12px 22px' }}>
                    <span>Send magic link</span><span className="arrow">→</span>
                  </button>
                </form>
              )}
              {magicErr && <p className="admin-auth-err">{magicErr}</p>}
            </>
          )}
          {session && !authedAdmin && (
            <>
              <p className="admin-sub">Signed in as <strong>{session.user.email}</strong>{adminCheckErr ? '. Admin allowlist check failed:' : ", but this email isn't on the admin allowlist."}</p>
              {adminCheckErr ? (
                <>
                  <p className="admin-auth-err" style={{ background: 'var(--bg-2)', padding: '10px 14px', borderRadius: 8 }}>
                    <strong>Error:</strong> {adminCheckErr}
                  </p>
                  {/infinite recursion/i.test(adminCheckErr) && (
                    <>
                      <p className="admin-sub" style={{ fontSize: 13, marginTop: 12 }}>
                        Looks like the RLS recursion fix wasn't run yet. Open Supabase SQL Editor and run:
                      </p>
                      <pre className="admin-setup-code">{`drop policy if exists admin_users_self_read on public.admin_users;
create policy admin_users_self_read on public.admin_users
  for select using (email = auth.email());`}</pre>
                    </>
                  )}
                </>
              ) : (
                <p className="admin-sub" style={{ fontSize: 13 }}>To grant access, run in Supabase SQL Editor:<br/>
                  <code style={{ background: 'var(--bg-2)', padding: '6px 10px', borderRadius: 6, display: 'inline-block', marginTop: 8 }}>
                    insert into admin_users (email) values ('{session.user.email}');
                  </code>
                </p>
              )}
              <div style={{ display: 'flex', gap: 8, marginTop: 16, flexWrap: 'wrap' }}>
                <button
                  className="btn"
                  onClick={() => {
                    // Reset persisted route so we don't bounce back here on
                    // reload, then navigate to home (no hash). Uses the
                    // current user's scoped bucket — the unscoped blob
                    // has been deprecated for security.
                    try {
                      let uid = null;
                      try {
                        const cur = window.MR && window.MR.user && window.MR.user.current ? window.MR.user.current() : null;
                        uid = (cur && cur.session && cur.session.user && cur.session.user.id) || null;
                      } catch {}
                      const key = 'parentstack-v1:' + (uid || 'guest');
                      const raw = localStorage.getItem(key);
                      const s = raw ? JSON.parse(raw) : {};
                      s.route = 'discover';
                      s.routeParam = null;
                      localStorage.setItem(key, JSON.stringify(s));
                    } catch (e) {}
                    window.location.href = window.location.origin + '/';
                  }}
                  style={{ width: 'auto', padding: '10px 18px' }}
                >
                  <span>Back to MagicRascals</span><span className="arrow">→</span>
                </button>
                <button className="btn btn-ghost" onClick={() => location.reload()} style={{ width: 'auto', padding: '10px 18px' }}>Retry</button>
                <button className="btn btn-ghost" onClick={signOut} style={{ width: 'auto', padding: '10px 18px' }}>Sign out</button>
              </div>
            </>
          )}
        </div>
      </div>
    );
  }

  // ─── Render: admin panel ───
  const counts = products.reduce((acc, p) => { acc[p.status] = (acc[p.status] || 0) + 1; return acc; }, { draft: 0, published: 0, archived: 0 });

  return (
    <div className="page admin-page">
      <div className="admin-head">
        <div>
          <div className="page-eyebrow">Admin · curate</div>
          <h1 className="page-title">Products.</h1>
          <p className="admin-sub">{products.length} loaded · {counts.published || 0} published · {counts.draft || 0} draft</p>
        </div>
        <div className="admin-head-actions">
          <button className="btn btn-ghost" onClick={() => setImporterOpen(true)} style={{ width: 'auto', padding: '11px 18px' }}>
            <span>Import from URL</span><span className="arrow">↗</span>
          </button>
          <button className="btn" onClick={() => setEditing(emptyProduct())} style={{ width: 'auto', padding: '11px 18px' }}>
            <span>+ New product</span>
          </button>
        </div>
      </div>

      {/* Tab nav: Products | Submissions */}
      <div className="admin-tabnav">
        <button
          type="button"
          className={`admin-tab${tab === 'products' ? ' is-on' : ''}`}
          onClick={() => setTab('products')}
        >Products <span className="admin-tab-count">{products.length}</span></button>
        <button
          type="button"
          className={`admin-tab${tab === 'submissions' ? ' is-on' : ''}`}
          onClick={() => setTab('submissions')}
        >Submissions {submissions.filter(s => s.status === 'pending').length > 0 && <span className="admin-tab-count admin-tab-count--alert">{submissions.filter(s => s.status === 'pending').length}</span>}</button>
        <button
          type="button"
          className={`admin-tab${tab === 'pro' ? ' is-on' : ''}`}
          onClick={() => setTab('pro')}
        >
          Pro access
          {proRequests.filter(r => r.status === 'requested').length > 0 && (
            <span className="admin-tab-count admin-tab-count--alert">
              {proRequests.filter(r => r.status === 'requested').length}
            </span>
          )}
        </button>
      </div>

      {tab === 'products' && (
        <div className="admin-toolbar">
          <input className="admin-search" placeholder="Search by name or brand…" value={search} onChange={(e) => setSearch(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') refresh(); }} />
          <div className="admin-filterpills">
            {['all','draft','published','archived'].map(s => (
              <button key={s} className={`admin-filterpill${statusFilter === s ? ' is-on' : ''}`} onClick={() => setStatusFilter(s)}>
                {s}{s !== 'all' && counts[s] != null ? ` · ${counts[s]}` : ''}
              </button>
            ))}
          </div>
          <button className="btn btn-ghost" onClick={refresh} style={{ width: 'auto', padding: '8px 14px', fontSize: 12.5 }}>Refresh</button>
          <button className="btn btn-ghost" onClick={signOut} style={{ width: 'auto', padding: '8px 14px', fontSize: 12.5, marginLeft: 'auto' }}>Sign out</button>
        </div>
      )}

      {tab === 'submissions' && (
        <div className="admin-toolbar">
          <div className="admin-filterpills">
            {['pending','approved','rejected','all'].map(s => (
              <button key={s} className={`admin-filterpill${submissionFilter === s ? ' is-on' : ''}`} onClick={() => setSubmissionFilter(s)}>
                {s}
              </button>
            ))}
          </div>
          <button className="btn btn-ghost" onClick={refreshSubmissions} style={{ width: 'auto', padding: '8px 14px', fontSize: 12.5 }}>Refresh</button>
          <button className="btn btn-ghost" onClick={signOut} style={{ width: 'auto', padding: '8px 14px', fontSize: 12.5, marginLeft: 'auto' }}>Sign out</button>
        </div>
      )}

      {tab === 'products' && (loading ? (
        <div className="admin-empty">Loading…</div>
      ) : products.length === 0 ? (
        <div className="admin-empty">
          <h3>No products yet.</h3>
          <p>Import from a URL or create one manually to get started.</p>
        </div>
      ) : (
        <table className="admin-table">
          <thead>
            <tr>
              <th></th>
              <th>Name</th>
              <th>Brand</th>
              <th>Category</th>
              <th>Age</th>
              <th>Price</th>
              <th>Status</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            {products.map(p => (
              <tr key={p.id} onClick={() => setEditing(p)}>
                <td>
                  {p.image_url ? (
                    <img src={p.image_url} alt="" className="admin-thumb" />
                  ) : <div className="admin-thumb admin-thumb--empty" />}
                </td>
                <td className="admin-cell-name">
                  <div>{p.name || <em style={{ color: 'var(--ink-3)' }}>(unnamed)</em>}</div>
                  {p.featured && <span className="admin-tag admin-tag--featured">★ featured</span>}
                </td>
                <td>{p.brand}</td>
                <td>{p.category}</td>
                <td>{ageRange(p)}</td>
                <td>{p.price != null ? `${p.currency || 'USD'} ${p.price}` : '—'}</td>
                <td><span className={`admin-status admin-status--${p.status}`}>{p.status}</span></td>
                <td><button className="admin-rowbtn" onClick={(e) => { e.stopPropagation(); setEditing(p); }}>Edit →</button></td>
              </tr>
            ))}
          </tbody>
        </table>
      ))}

      {tab === 'submissions' && (submissionsLoading ? (
        <div className="admin-empty">Loading…</div>
      ) : submissions.length === 0 ? (
        <div className="admin-empty">
          <h3>No submissions {submissionFilter !== 'all' && `(${submissionFilter})`}.</h3>
          <p>When users paste a URL we don't have, the extracted data appears here for review.</p>
        </div>
      ) : (
        <table className="admin-table admin-table--subs">
          <thead>
            <tr>
              <th></th>
              <th>Name / source</th>
              <th>Brand</th>
              <th>Price</th>
              <th>Submitter</th>
              <th>Status</th>
              <th>Submitted</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            {submissions.map(s => {
              const e = s.extracted || {};
              const when = s.created_at ? new Date(s.created_at).toLocaleDateString() : '';
              const sourceHost = (() => { try { return new URL(s.source_url).hostname.replace(/^www\./, ''); } catch { return s.source_url; } })();
              return (
                <tr key={s.id}>
                  <td>
                    {e.image
                      ? <img src={e.image} alt="" className="admin-thumb" onError={(ev) => { ev.currentTarget.style.display = 'none'; }} />
                      : <div className="admin-thumb admin-thumb--empty" />}
                  </td>
                  <td className="admin-cell-name">
                    <div>{e.title || <em style={{ color: 'var(--ink-3)' }}>(no title)</em>}</div>
                    <a href={s.source_url} target="_blank" rel="noopener noreferrer" className="admin-sub-link">{sourceHost} ↗</a>
                  </td>
                  <td>{e.brand || '—'}</td>
                  <td>{e.price != null ? `${e.currency || ''} ${e.price}` : '—'}</td>
                  <td className="admin-sub-submitter">{s.submitted_by ? s.submitted_by.slice(0, 8) + '…' : '—'}</td>
                  <td><span className={`admin-status admin-status--${s.status}`}>{s.status}</span></td>
                  <td className="admin-sub-when">{when}</td>
                  <td>
                    {s.status === 'pending' && (
                      <div className="admin-sub-actions">
                        <button className="admin-rowbtn admin-rowbtn--primary" onClick={(ev) => { ev.stopPropagation(); promoteSubmission(s); }}>Promote →</button>
                        <button className="admin-rowbtn admin-rowbtn--ghost" onClick={(ev) => { ev.stopPropagation(); rejectSubmission(s); }}>Reject</button>
                      </div>
                    )}
                    {s.status === 'approved' && s.promoted_product_id && (
                      <button className="admin-rowbtn" onClick={(ev) => {
                        ev.stopPropagation();
                        // Open the promoted product for editing
                        const promoted = products.find(p => p.id === s.promoted_product_id);
                        if (promoted) setEditing(promoted);
                        else showToast('Promoted product not in current list — switch to Products tab to find it.');
                      }}>Open →</button>
                    )}
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      ))}

      {editing && (
        <ProductEditor
          product={editing}
          onClose={() => setEditing(null)}
          onSaved={async (saved, action) => {
            // If the editor was opened from a submission row, mark the
            // submission promoted and stash a back-link.
            if (editing._fromSubmissionId && saved && saved.id) {
              try {
                await window.MR.supabase
                  .from('product_submissions')
                  .update({ status: 'approved', promoted_product_id: saved.id })
                  .eq('id', editing._fromSubmissionId);
              } catch (e) { /* non-fatal */ }
            }
            setEditing(null);
            showToast(action === 'created' ? 'Product created' : action === 'deleted' ? 'Deleted' : 'Saved');
            refresh();
            if (tab === 'submissions') refreshSubmissions();
          }}
          onError={(msg) => showToast('Error: ' + msg)}
        />
      )}

      {importerOpen && (
        <UrlImporter
          onClose={() => setImporterOpen(false)}
          onImported={(prefill) => { setImporterOpen(false); setEditing({ ...emptyProduct(), ...prefill }); }}
        />
      )}

      {/* Pro access — review pending requests, approve or deny. */}
      {tab === 'pro' && (
        <div className="admin-toolbar">
          <div className="admin-filterpills">
            {['requested','approved','denied','all'].map(s => (
              <button key={s} className={`admin-filterpill${proFilter === s ? ' is-on' : ''}`} onClick={() => setProFilter(s)}>
                {s} {s !== 'all' ? `· ${proRequests.filter(r => r.status === s).length}` : `· ${proRequests.length}`}
              </button>
            ))}
          </div>
          <button className="btn btn-ghost" onClick={refreshPro} style={{ width: 'auto', padding: '8px 14px', fontSize: 12.5 }}>Refresh</button>
          <button className="btn btn-ghost" onClick={signOut} style={{ width: 'auto', padding: '8px 14px', fontSize: 12.5, marginLeft: 'auto' }}>Sign out</button>
        </div>
      )}
      {tab === 'pro' && (proLoading ? (
        <div className="admin-empty">Loading…</div>
      ) : proErr ? (
        <div className="admin-empty" style={{ color: '#a8472f' }}>{proErr}</div>
      ) : (
        (() => {
          const filtered = proFilter === 'all'
            ? proRequests
            : proRequests.filter(r => r.status === proFilter);
          if (filtered.length === 0) {
            return <div className="admin-empty">No {proFilter === 'all' ? '' : proFilter + ' '}requests.</div>;
          }
          return (
            <div className="admin-prolist">
              {filtered.map(r => (
                <div key={r.user_id} className={`admin-prorow admin-prorow--${r.status}`}>
                  <div className="admin-prorow-main">
                    <div className="admin-prorow-id">
                      {proUserEmails[r.user_id] || r.user_id}
                    </div>
                    {r.note && <div className="admin-prorow-note">"{r.note}"</div>}
                    <div className="admin-prorow-meta">
                      Requested {r.requested_at ? new Date(r.requested_at).toLocaleString() : '—'}
                      {r.reviewed_at && ` · Reviewed ${new Date(r.reviewed_at).toLocaleString()} by ${r.reviewer_email || '—'}`}
                      {` · Status: ${r.status}`}
                    </div>
                  </div>
                  <div className="admin-prorow-actions">
                    {r.status !== 'approved' && (
                      <button type="button" className="btn" style={{ width: 'auto', padding: '7px 14px', fontSize: 12 }} onClick={() => setProStatus(r.user_id, 'approved')}>
                        ✓ Approve
                      </button>
                    )}
                    {r.status !== 'denied' && (
                      <button type="button" className="btn btn-ghost" style={{ width: 'auto', padding: '7px 14px', fontSize: 12 }} onClick={() => setProStatus(r.user_id, 'denied')}>
                        Deny
                      </button>
                    )}
                  </div>
                </div>
              ))}
            </div>
          );
        })()
      ))}

      <div className={`saved-toast${toast ? ' is-show' : ''}`}>
        <span>{toast}</span>
      </div>
    </div>
  );
}

function ageRange(p) {
  if (p.age_min == null && p.age_max == null) return '—';
  const fmt = (m) => m == null ? '?' : m < 0 ? 'pre' : m < 24 ? `${m}m` : `${Math.floor(m/12)}y`;
  return `${fmt(p.age_min)}–${fmt(p.age_max)}`;
}

// ─────────────────── URL importer ───────────────────
function UrlImporter({ onClose, onImported }) {
  const [url, setUrl] = useState('');
  const [busy, setBusy] = useState(false);
  const [err, setErr] = useState('');

  const submit = async (e) => {
    e.preventDefault();
    setErr(''); setBusy(true);
    try {
      const r = await fetch('/api/og-fetch?url=' + encodeURIComponent(url.trim()));
      const j = await r.json();
      if (!j.ok) throw new Error(j.error || 'Fetch failed');
      const d = j.data || {};
      onImported({
        name: d.title || '',
        brand: d.brand || '',
        description: d.description || '',
        price: d.price != null ? Number(d.price) : null,
        currency: d.currency || 'USD',
        image_url: d.image || '',
        gallery_urls: (d.gallery || []).slice(0, 6),
        primary_url: d.sourceUrl || url.trim(),
        source_url: d.sourceUrl || url.trim(),
        imported_via: 'og',
      });
    } catch (e) {
      setErr(e.message || String(e));
    } finally {
      setBusy(false);
    }
  };

  return (
    <>
      <div className="share-scrim is-open" onClick={onClose} />
      <form className="share-modal is-open admin-modal" onSubmit={submit}>
        <h3 className="share-h">Import from URL</h3>
        <p className="share-sub">Paste a product page URL. We'll grab the title, image, brand, price, and description from its OpenGraph / JSON-LD metadata, then you confirm.</p>
        <input
          className="gift-input"
          autoFocus
          placeholder="https://www.lovevery.com/products/the-play-gym"
          value={url}
          onChange={(e) => setUrl(e.target.value)}
        />
        {err && <p style={{ color: '#cf5d4a', fontSize: 13, marginTop: 8 }}>{err}</p>}
        <div style={{ marginTop: 22, display: 'flex', justifyContent: 'flex-end', gap: 8 }}>
          <button type="button" className="btn btn-ghost" onClick={onClose} style={{ width: 'auto', padding: '10px 18px' }}>Cancel</button>
          <button type="submit" className="btn" disabled={busy || !url.trim()} style={{ width: 'auto', padding: '10px 18px', opacity: busy || !url.trim() ? 0.5 : 1 }}>
            <span>{busy ? 'Fetching…' : 'Import'}</span><span className="arrow">→</span>
          </button>
        </div>
      </form>
    </>
  );
}

// ─────────────────── Product editor ───────────────────
function ProductEditor({ product, onClose, onSaved, onError }) {
  const [draft, setDraft] = useState(() => ({ ...product }));
  const [saving, setSaving] = useState(false);
  const isNew = !product.id;

  const set = (patch) => setDraft(d => ({ ...d, ...patch }));
  const setArr = (key, val) => set({ [key]: val });
  const toggleInArr = (key, item) => {
    const arr = draft[key] || [];
    set({ [key]: arr.includes(item) ? arr.filter(x => x !== item) : [...arr, item] });
  };

  const save = async (status) => {
    setSaving(true);
    const sb = window.MR.supabase;
    const payload = { ...draft };
    if (status) payload.status = status;
    // Numeric coercions
    if (payload.price === '' || payload.price == null) payload.price = null;
    else payload.price = Number(payload.price);
    if (payload.price_high === '' || payload.price_high == null) payload.price_high = null;
    else payload.price_high = Number(payload.price_high);
    if (payload.age_min === '' || payload.age_min == null) payload.age_min = null;
    else payload.age_min = parseInt(payload.age_min, 10);
    if (payload.age_max === '' || payload.age_max == null) payload.age_max = null;
    else payload.age_max = parseInt(payload.age_max, 10);

    let res;
    if (isNew) {
      delete payload.id;
      res = await sb.from('products').insert(payload).select().single();
    } else {
      const id = payload.id;
      delete payload.id; delete payload.created_at; delete payload.updated_at;
      res = await sb.from('products').update(payload).eq('id', id).select().single();
    }
    setSaving(false);
    if (res.error) { onError(res.error.message); return; }
    onSaved(res.data, isNew ? 'created' : 'updated');
  };

  const remove = async () => {
    if (!confirm('Delete this product? This cannot be undone.')) return;
    const { error } = await window.MR.supabase.from('products').delete().eq('id', product.id);
    if (error) { onError(error.message); return; }
    onSaved(null, 'deleted');
  };

  return (
    <>
      <div className="share-scrim is-open" onClick={onClose} />
      <div className="share-modal is-open admin-editor">
        <div className="admin-editor-head">
          <h3 className="share-h" style={{ marginBottom: 4 }}>{isNew ? 'New product' : 'Edit product'}</h3>
          <p className="share-sub" style={{ margin: 0 }}>{isNew ? 'Fill what you have. You can come back later.' : `Last updated ${product.updated_at ? new Date(product.updated_at).toLocaleString() : '—'}`}</p>
        </div>

        <div className="admin-editor-body">
          {draft.image_url && (
            <div className="admin-editor-imgpreview">
              <img src={draft.image_url} alt="" />
            </div>
          )}

          <Section title="Identity">
            <Field label="Name" value={draft.name} onChange={(v) => set({ name: v })} placeholder="Stokke Sleepi Crib" />
            <Field label="Brand" value={draft.brand} onChange={(v) => set({ brand: v })} placeholder="Stokke" />
            <Field label="Short benefit" value={draft.benefit} onChange={(v) => set({ benefit: v })} placeholder="Heirloom nursery piece" />
            <Field label="Image URL" value={draft.image_url} onChange={(v) => set({ image_url: v })} placeholder="https://…" />
          </Section>

          <Section title="Editorial">
            <FieldArea label="Why we love it" value={draft.why} onChange={(v) => set({ why: v })} placeholder="The kind of cot that earns its keep through years of nighttime use." rows={3} />
            <FieldArea label="Description" value={draft.description} onChange={(v) => set({ description: v })} placeholder="Long marketing description (used on detail panel)." rows={3} />
            <FieldArea label="How you use it" value={draft.how_to_use} onChange={(v) => set({ how_to_use: v })} rows={3} />
          </Section>

          <Section title="Classification">
            <FieldRow>
              <FieldSelect label="Category" value={draft.category} options={CATEGORY_OPTIONS} onChange={(v) => set({ category: v })} />
              <FieldSelect label="Stage" value={draft.stage} options={STAGE_OPTIONS} onChange={(v) => set({ stage: v })} />
            </FieldRow>
            <FieldRow>
              <FieldNum label="Age min (months)" value={draft.age_min} onChange={(v) => set({ age_min: v })} placeholder="0 / -1 for pre-baby" />
              <FieldNum label="Age max (months)" value={draft.age_max} onChange={(v) => set({ age_max: v })} placeholder="36" />
            </FieldRow>
            <ChipGroup label="Learning focus" options={LEARNING_OPTIONS} selected={draft.learning || []} onToggle={(v) => toggleInArr('learning', v)} />
            <FieldArr label="Tags (comma-separated)" value={(draft.tags || []).join(', ')} onChange={(v) => setArr('tags', v.split(',').map(s => s.trim()).filter(Boolean))} placeholder="montessori, sustainable, open-ended" />
          </Section>

          <Section title="Pricing">
            <FieldRow>
              <FieldNum label="Price" value={draft.price} onChange={(v) => set({ price: v })} placeholder="129" step="0.01" />
              <FieldNum label="MSRP" value={draft.price_high} onChange={(v) => set({ price_high: v })} placeholder="149" step="0.01" />
              <Field label="Currency" value={draft.currency} onChange={(v) => set({ currency: v.toUpperCase() })} placeholder="USD" />
            </FieldRow>
          </Section>

          <Section title="At-a-glance facts">
            <Field label="Size" value={draft.size} onChange={(v) => set({ size: v })} />
            <Field label="Materials" value={draft.materials} onChange={(v) => set({ materials: v })} />
            <Field label="Made in" value={draft.made_in} onChange={(v) => set({ made_in: v })} />
          </Section>

          <Section title="Retail">
            <FieldRow>
              <Field label="Primary retailer" value={draft.primary_retailer} onChange={(v) => set({ primary_retailer: v })} placeholder="Pottery Barn Kids" />
              <Field label="Primary URL (affiliate)" value={draft.primary_url} onChange={(v) => set({ primary_url: v })} placeholder="https://…" />
            </FieldRow>
          </Section>

          <Section title="Curation">
            <FieldRow>
              <FieldSelect label="Status" value={draft.status} options={STATUS_OPTIONS} onChange={(v) => set({ status: v })} />
              <FieldCheck label="Featured" value={draft.featured} onChange={(v) => set({ featured: v })} />
            </FieldRow>
            <FieldArea label="Internal notes" value={draft.notes} onChange={(v) => set({ notes: v })} rows={2} />
          </Section>
        </div>

        <div className="admin-editor-foot">
          {!isNew && (
            <button type="button" className="btn btn-ghost" onClick={remove} style={{ width: 'auto', padding: '10px 14px', color: '#cf5d4a' }}>Delete</button>
          )}
          <button type="button" className="btn btn-ghost" onClick={onClose} style={{ width: 'auto', padding: '10px 18px', marginLeft: 'auto' }}>Cancel</button>
          <button type="button" className="btn btn-ghost" onClick={() => save('draft')} disabled={saving} style={{ width: 'auto', padding: '10px 18px' }}>Save as draft</button>
          <button type="button" className="btn" onClick={() => save('published')} disabled={saving || !draft.name} style={{ width: 'auto', padding: '10px 18px' }}>
            <span>{saving ? 'Saving…' : 'Save & publish'}</span><span className="arrow">→</span>
          </button>
        </div>
      </div>
    </>
  );
}

// ─────────────────── Tiny field components ───────────────────
function Section({ title, children }) {
  return (
    <div className="admin-section">
      <div className="admin-section-h">{title}</div>
      <div className="admin-section-body">{children}</div>
    </div>
  );
}
function FieldRow({ children }) { return <div className="admin-fieldrow">{children}</div>; }
function Field({ label, value, onChange, placeholder, type='text' }) {
  return (
    <label className="admin-field">
      <span>{label}</span>
      <input className="gift-input" type={type} value={value || ''} onChange={(e) => onChange(e.target.value)} placeholder={placeholder} />
    </label>
  );
}
function FieldNum({ label, value, onChange, placeholder, step='1' }) {
  return (
    <label className="admin-field">
      <span>{label}</span>
      <input className="gift-input" type="number" step={step} value={value == null ? '' : value} onChange={(e) => onChange(e.target.value)} placeholder={placeholder} />
    </label>
  );
}
function FieldArea({ label, value, onChange, placeholder, rows=2 }) {
  return (
    <label className="admin-field">
      <span>{label}</span>
      <textarea className="gift-input gift-textarea" rows={rows} value={value || ''} onChange={(e) => onChange(e.target.value)} placeholder={placeholder} />
    </label>
  );
}
function FieldSelect({ label, value, options, onChange }) {
  return (
    <label className="admin-field">
      <span>{label}</span>
      <select className="gift-input" value={value || ''} onChange={(e) => onChange(e.target.value)} style={{ appearance: 'auto', cursor: 'pointer' }}>
        {options.map(o => <option key={o} value={o}>{o}</option>)}
      </select>
    </label>
  );
}
function FieldCheck({ label, value, onChange }) {
  return (
    <label className="admin-field admin-field--check">
      <input type="checkbox" checked={!!value} onChange={(e) => onChange(e.target.checked)} />
      <span>{label}</span>
    </label>
  );
}
function FieldArr({ label, value, onChange, placeholder }) {
  return <Field label={label} value={value} onChange={onChange} placeholder={placeholder} />;
}
function ChipGroup({ label, options, selected, onToggle }) {
  return (
    <div className="admin-field">
      <span>{label}</span>
      <div className="admin-chips">
        {options.map(o => (
          <button key={o} type="button" className={`admin-chip${selected.includes(o) ? ' is-on' : ''}`} onClick={() => onToggle(o)}>{o}</button>
        ))}
      </div>
    </div>
  );
}

// ─────────────────── Setup gate (when config is blank) ───────────────────
function AdminSetupGate() {
  return (
    <div className="page admin-page">
      <div className="admin-auth-card">
        <div className="page-eyebrow">Admin · setup</div>
        <h1 className="page-title">One step left.</h1>
        <p className="admin-sub">Fill in your Supabase project URL and anon key in <code>admin-config.js</code>. Then refresh this page.</p>
        <ol className="admin-setup-list">
          <li>Create a free project at <a href="https://supabase.com/dashboard" target="_blank" rel="noreferrer">supabase.com/dashboard</a>.</li>
          <li>Open <strong>SQL Editor → New query</strong>, paste the contents of <code>admin/schema.sql</code>, and run it.</li>
          <li>Open <strong>Settings → API</strong>, copy <strong>Project URL</strong> and <strong>anon public</strong> key.</li>
          <li>Paste both into <code>admin-config.js</code>:</li>
        </ol>
        <pre className="admin-setup-code">{`window.MR_ADMIN_CONFIG = {
  SUPABASE_URL:  'https://xxx.supabase.co',
  SUPABASE_ANON: 'eyJhbGc...',
};`}</pre>
        <p className="admin-sub" style={{ fontSize: 13 }}>The schema seeds <code>sam@magicrascals.com</code> as the admin email. Edit <code>admin/schema.sql</code> if your email is different, or run <code>insert into admin_users (email) values ('you@…');</code> later.</p>
      </div>
    </div>
  );
}

window.AdminPage = AdminPage;
