// Public registry guest view + claim flow.
//
// URL: /#registry?token=ABCDEF (the share_token on a user_lists row).
// Renders a read-only, gift-buyer-styled view of the list — no admin
// controls, no edit affordances. Each item gets a single "I'm getting
// this →" CTA that opens a small claim form: name + email + optional note.
//
// Claims are anonymous (no Supabase auth required for buyers).

const { useEffect: _re, useState: _rs } = React;

function RegistryGuestPage({ token, onBack }) {
  const [state, setState] = _rs('loading');      // 'loading' | 'loaded' | 'error'
  const [list, setList] = _rs(null);
  const [items, setItems] = _rs([]);
  const [claims, setClaims] = _rs([]);
  const [err, setErr] = _rs('');
  const [claimItem, setClaimItem] = _rs(null);
  const [claimToast, setClaimToast] = _rs('');
  // After a successful claim we reveal the shipping address if the owner
  // has opted in to sharing it. Stick around until the user dismisses.
  const [showAddress, setShowAddress] = _rs(false);

  _re(() => {
    if (!token || !window.MR || !window.MR.supabase) {
      setErr('Missing or invalid registry link.');
      setState('error');
      return;
    }
    let cancelled = false;
    (async () => {
      // 1. Look up the root node by share_token. RLS allows anonymous reads
      //    on rows whose root has a non-null share_token.
      const { data: roots, error: rootErr } = await window.MR.supabase
        .from('list_nodes')
        .select('id, name, description, kind, cover_color, cover_icon, shipping_address, shipping_address_public, share_token')
        .eq('share_token', token)
        .is('parent_id', null)
        .limit(1);
      if (cancelled) return;
      if (rootErr) { setErr(rootErr.message); setState('error'); return; }
      if (!roots || !roots.length) { setErr('This registry link is invalid or has expired.'); setState('error'); return; }
      const found = roots[0];
      setList(found);

      // 2. Pull every descendant node + existing claims in parallel. The
      //    registry view flattens slots — the gift-buyer sees a list of
      //    items they can claim, regardless of where they live in the tree.
      const [nodesRes, claimsRes] = await Promise.all([
        window.MR.supabase
          .from('list_nodes')
          .select('*')
          .eq('root_id', found.id)
          .eq('type', 'item')
          .order('position', { ascending: true }),
        window.MR.supabase
          .from('registry_claims')
          .select('node_id, buyer_name, note')
          .eq('root_id', found.id),
      ]);
      if (cancelled) return;
      if (nodesRes.error) { setErr(nodesRes.error.message); setState('error'); return; }
      // The registry view only shows nodes flagged in_registry — or, if the
      // root's kind is 'registry', all picked items by default.
      const showAll = (found.kind === 'registry');
      const filtered = (nodesRes.data || []).filter(n =>
        showAll ? (n.picked || n.in_registry) : n.in_registry
      );
      setItems(filtered);
      if (claimsRes.data) setClaims(claimsRes.data);
      setState('loaded');
    })().catch(e => { if (!cancelled) { setErr(e.message); setState('error'); } });
    return () => { cancelled = true; };
  }, [token]);

  const claimedItemIds = new Set(claims.map(c => c.node_id || c.item_id));

  if (state === 'loading') {
    return <main className="registry-guest"><div className="registry-guest-empty">Reading the registry…</div></main>;
  }
  if (state === 'error') {
    return (
      <main className="registry-guest">
        <div className="registry-guest-empty">
          <h2 className="registry-guest-err-h">Couldn't open this registry</h2>
          <p>{err}</p>
          <button className="btn btn-ghost" onClick={onBack} style={{ width: 'auto', padding: '10px 18px' }}>
            <span>Back to MagicRascals</span>
          </button>
        </div>
      </main>
    );
  }

  const cover = (() => {
    if (!list) return null;
    const colors = window.LIST_COVER_COLORS_FALLBACK || [{ bg: '#fbf0d8', fg: '#b88339' }];
    return {
      bg: list.cover_color ? null : colors[0].bg,
      fg: list.cover_color ? null : colors[0].fg,
      icon: list.cover_icon || '🎀',
    };
  })();

  return (
    <main className="registry-guest">
      <header className="registry-guest-head">
        <div className="registry-guest-eyebrow">Public registry</div>
        <h1 className="registry-guest-h">{list.name}</h1>
        {list.description && <p className="registry-guest-sub">{list.description}</p>}
        <div className="registry-guest-meta">
          <span>{items.length} items</span>
          <span className="dot" />
          <span>{claimedItemIds.size} claimed</span>
        </div>
      </header>

      {showAddress && list.shipping_address && (
        <div className="registry-guest-addr">
          <div className="registry-guest-addr-eyebrow">📮 Shipping address</div>
          <div className="registry-guest-addr-body">
            {list.shipping_address.name && <div><strong>{list.shipping_address.name}</strong></div>}
            {list.shipping_address.line1 && <div>{list.shipping_address.line1}</div>}
            {list.shipping_address.line2 && <div>{list.shipping_address.line2}</div>}
            {(list.shipping_address.city || list.shipping_address.state || list.shipping_address.postcode) && (
              <div>{[list.shipping_address.city, list.shipping_address.state, list.shipping_address.postcode].filter(Boolean).join(' ')}</div>
            )}
            {list.shipping_address.country && <div>{list.shipping_address.country}</div>}
            {list.shipping_address.instructions && (
              <div className="registry-guest-addr-note">{list.shipping_address.instructions}</div>
            )}
          </div>
          <button type="button" className="registry-guest-addr-close" onClick={() => setShowAddress(false)} aria-label="Dismiss">×</button>
        </div>
      )}

      {items.length === 0 ? (
        <div className="registry-guest-empty">
          <p>The owner hasn't added anything to the registry yet.</p>
        </div>
      ) : (
        <ul className="registry-guest-items">
          {items.map(item => {
            const claimed = claimedItemIds.has(item.id);
            const itemClaim = claims.find(c => (c.node_id || c.item_id) === item.id);
            // Resolve display fields from catalog (if product_id) or custom blob.
            // Without this fallback, catalog-backed registry items render as "—".
            const product = item.product_id && window.PRODUCTS
              ? window.PRODUCTS.find(p => p.id === item.product_id)
              : null;
            const img   = product ? product.img : item.custom_image_url;
            const name  = product ? product.name : (item.custom_name || 'Item');
            const brand = product ? product.brand : item.custom_brand;
            const price = product ? product.price : item.custom_price;
            const currency = product ? (product.currency || 'AUD') : (item.custom_currency || 'AUD');
            return (
              <li key={item.id} className={`registry-guest-row${claimed ? ' is-claimed' : ''}`}>
                <div className="registry-guest-thumb">
                  {img
                    ? <SmartImage src={img} alt={name} fallbackLabel={brand || name} />
                    : <span className="registry-guest-thumb-empty">—</span>}
                </div>
                <div className="registry-guest-body">
                  {brand && <div className="registry-guest-brand">{brand}</div>}
                  <h3 className="registry-guest-name">{name}</h3>
                  {price != null && (
                    <div className="registry-guest-price">{currency === 'AUD' ? 'A$' : '$'}{price}</div>
                  )}
                  {item.quantity_needed > 1 && (
                    <div className="registry-guest-qty">Wanted: {item.quantity_needed}</div>
                  )}
                </div>
                <div className="registry-guest-actions">
                  {claimed ? (
                    <div className="registry-guest-claimed">
                      <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4"><path d="M5 12l5 5L20 7"/></svg>
                      Claimed by {itemClaim?.buyer_name || 'someone'}
                    </div>
                  ) : (
                    <button type="button" className="btn" onClick={() => setClaimItem(item)} style={{ width: 'auto', padding: '10px 16px' }}>
                      <span>I'm getting this</span>
                      <span className="arrow">→</span>
                    </button>
                  )}
                </div>
              </li>
            );
          })}
        </ul>
      )}

      <ClaimItemModal
        open={!!claimItem}
        listId={list && list.id}
        item={claimItem}
        onClose={() => setClaimItem(null)}
        onClaimed={(buyer_name) => {
          setClaims(prev => [...prev, { node_id: claimItem.id, buyer_name }]);
          setClaimItem(null);
          setClaimToast(`Thanks ${buyer_name}! The owner has been notified.`);
          setTimeout(() => setClaimToast(''), 4000);
          if (list && list.shipping_address_public && list.shipping_address) {
            setShowAddress(true);
          }
        }}
      />

      {claimToast && (
        <div className="registry-guest-toast">
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M5 12l5 5L20 7"/></svg>
          <span>{claimToast}</span>
        </div>
      )}
    </main>
  );
}

function ClaimItemModal({ open, item, listId, onClose, onClaimed }) {
  const [name, setName] = _rs('');
  const [email, setEmail] = _rs('');
  const [note, setNote] = _rs('');
  const [anonymous, setAnonymous] = _rs(false);
  const [busy, setBusy] = _rs(false);
  const [err, setErr] = _rs('');

  _re(() => {
    if (open) { setName(''); setEmail(''); setNote(''); setAnonymous(false); setErr(''); setBusy(false); }
  }, [open]);

  if (!open || !item) return null;

  const submit = async (e) => {
    e.preventDefault();
    if (!anonymous && !name.trim()) {
      setErr('Add your name — or check "anonymous" to claim privately.');
      return;
    }
    setBusy(true);
    try {
      // Anonymous claim: name stored as "Anonymous" so the owner sees a
      // generic chip. Email is never required.
      const buyerName = anonymous ? 'Anonymous' : name.trim();
      const { error } = await window.MR.supabase.from('registry_claims').insert({
        root_id: listId,
        node_id: item.id,
        buyer_name: buyerName,
        buyer_email: anonymous ? null : (email.trim() || null),
        note: note.trim() || null,
      });
      if (error) { setErr(error.message); setBusy(false); return; }
      onClaimed(buyerName);
    } catch (e) {
      setErr(e.message || 'Could not claim — try again?');
      setBusy(false);
    }
  };

  return (
    <>
      <div className="auth-scrim" onClick={onClose} />
      <div className="auth-modal claim-modal">
        <div className="auth-eyebrow">You're getting</div>
        <h2 className="auth-h">{item.custom_name || 'this gift'}</h2>
        <p className="auth-sub">
          Tell the owner you're handling this one. They'll mark it as claimed
          so nobody else doubles up.
        </p>
        <form onSubmit={submit}>
          <label className="auth-field" style={{ opacity: anonymous ? 0.4 : 1, pointerEvents: anonymous ? 'none' : 'auto' }}>
            <span className="auth-lbl">Your name</span>
            <input type="text" required={!anonymous} autoFocus={!anonymous} className="auth-input" value={name} onChange={(e) => setName(e.target.value)} placeholder="Sarah" />
          </label>
          <label className="auth-field" style={{ opacity: anonymous ? 0.4 : 1, pointerEvents: anonymous ? 'none' : 'auto' }}>
            <span className="auth-lbl">Email <em style={{ fontStyle: 'normal', color: 'var(--ink-3)', fontSize: 11 }}>(optional)</em></span>
            <input type="email" className="auth-input" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="for thank-you notes" />
          </label>
          <label className="auth-field">
            <span className="auth-lbl">Note for the parents <em style={{ fontStyle: 'normal', color: 'var(--ink-3)', fontSize: 11 }}>(optional)</em></span>
            <textarea className="auth-input" rows={3} value={note} onChange={(e) => setNote(e.target.value)} placeholder="With love from grandma" />
          </label>
          {/* Anonymous toggle — when on, the owner sees "Anonymous gift"
              instead of your name. Note still comes through if you add one. */}
          <label className="auth-checkrow" style={{ marginTop: 10 }}>
            <input type="checkbox" checked={anonymous} onChange={(e) => setAnonymous(e.target.checked)} />
            <span>
              <strong>Claim anonymously</strong> — the owner sees "Anonymous gift" and won't know it's from you.
            </span>
          </label>
          {err && <div className="auth-err">{err}</div>}
          <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end', marginTop: 18 }}>
            <button type="button" className="btn btn-ghost" onClick={onClose} style={{ width: 'auto', padding: '10px 16px' }}><span>Cancel</span></button>
            <button type="submit" className="btn" disabled={busy} style={{ width: 'auto', padding: '10px 18px' }}>
              <span className="btn-row">{busy ? 'Saving…' : 'Confirm — I\'m getting this'}</span>
              <span className="arrow">→</span>
            </button>
          </div>
        </form>
      </div>
    </>
  );
}

window.RegistryGuestPage = RegistryGuestPage;
