// screen-browse.jsx — open marketplace feed. Backers find action to buy.

const { useState: bU, useEffect: bE, useMemo: bM } = React;

function BrowseScreen({ onNav }) {
  const { Footer, fmtMoney, fmtPct } = window.PJ_UI;
  const [listings, setListings] = bU([]);
  const [reps, setReps] = bU({}); // handle → rep
  const [loading, setLoading] = bU(true);
  const [err, setErr] = bU(null);

  const [tournamentFilter, setTournamentFilter] = bU('');
  const [maxMarkup, setMaxMarkup] = bU(2.0);
  const [maxBuyIn, setMaxBuyIn] = bU('');
  const [sort, setSort] = bU('reputation'); // reputation | markup | recent | start

  bE(() => {
    (async () => {
      setLoading(true);
      try {
        const list = await window.pjListMarketplace({});
        setListings(list);
        // Fetch reputation per listing — keyed by the listing's player_device_id
        // so spoofers on a new device can't inherit another device's rep.
        const repMap = {};
        await Promise.all(list.map(async (l) => {
          const key = l.player_handle.toLowerCase();
          if (repMap[key]) return; // first listing's device wins for this handle
          try {
            const r = await window.pjGetReputationForListing(l);
            repMap[key] = r;
          } catch (_) { repMap[key] = null; }
        }));
        setReps(repMap);
      } catch (e) {
        setErr(e.message || String(e));
      } finally {
        setLoading(false);
      }
    })();
  }, []);

  const filtered = bM(() => {
    let rows = listings.slice();
    if (tournamentFilter.trim()) {
      const q = tournamentFilter.trim().toLowerCase();
      rows = rows.filter(l => (l.tournament_name || '').toLowerCase().includes(q));
    }
    if (maxMarkup) rows = rows.filter(l => Number(l.markup) <= Number(maxMarkup) + 0.0001);
    if (maxBuyIn) rows = rows.filter(l => Number(l.buy_in) <= Number(maxBuyIn));

    if (sort === 'reputation') {
      rows.sort((a, b) => {
        const ra = reps[a.player_handle.toLowerCase()];
        const rb = reps[b.player_handle.toLowerCase()];
        const sa = ra ? (ra.locked_count || 0) : 0;
        const sb = rb ? (rb.locked_count || 0) : 0;
        return sb - sa;
      });
    } else if (sort === 'markup') {
      rows.sort((a, b) => Number(a.markup) - Number(b.markup));
    } else if (sort === 'recent') {
      rows.sort((a, b) => (b.created_at || '').localeCompare(a.created_at || ''));
    }
    return rows;
  }, [listings, reps, tournamentFilter, maxMarkup, maxBuyIn, sort]);

  return (
    <div className="page">
      <div className="eyebrow" style={{ marginBottom: 8, color: 'var(--green)' }}>◆ Marketplace</div>
      <h2 style={{
        fontFamily: 'var(--font-display)', fontSize: 40, fontWeight: 800,
        letterSpacing: '-0.025em', lineHeight: 1.02, margin: '0 0 8px', color: 'var(--text)'
      }}>Find action.</h2>
      <p style={{ color: 'var(--text-3)', marginBottom: 22, fontSize: 15 }}>
        Players offering pieces of their action. Tap a card to back.
      </p>

      {/* Filters */}
      <div style={{
        background: 'var(--bg-1)',
        border: '1px solid rgba(255,255,255,0.06)',
        borderRadius: 12,
        padding: 14,
        marginBottom: 18
      }}>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10, marginBottom: 12 }}>
          <input
            className="input"
            placeholder="Tournament"
            value={tournamentFilter}
            onChange={e => setTournamentFilter(e.target.value)}
          />
          <input
            className="input num"
            placeholder="Max buy-in"
            type="number"
            inputMode="numeric"
            value={maxBuyIn}
            onChange={e => setMaxBuyIn(e.target.value.replace(/[^0-9.]/g, ''))}
          />
        </div>
        <div className="mono" style={{
          fontSize: 10, letterSpacing: '0.14em', color: 'var(--text-3)',
          textTransform: 'uppercase', marginBottom: 6
        }}>Max markup — {Number(maxMarkup).toFixed(2)}x</div>
        <input
          type="range" min={1.0} max={2.0} step={0.05}
          value={maxMarkup}
          onChange={e => setMaxMarkup(Number(e.target.value))}
          style={{ width: '100%' }}
        />

        <div style={{ display: 'flex', gap: 6, marginTop: 12, flexWrap: 'wrap' }}>
          {['reputation', 'markup', 'recent'].map(k => (
            <button
              key={k}
              type="button"
              onClick={() => setSort(k)}
              style={{
                all: 'unset', cursor: 'pointer',
                padding: '6px 12px', borderRadius: 999,
                fontFamily: 'var(--font-mono)', fontSize: 10,
                letterSpacing: '0.12em', textTransform: 'uppercase',
                background: sort === k ? 'var(--green-soft)' : 'transparent',
                color: sort === k ? 'var(--green)' : 'var(--text-3)',
                border: '1px solid ' + (sort === k ? 'var(--green-line)' : 'rgba(255,255,255,0.08)')
              }}
            >
              Sort: {k}
            </button>
          ))}
        </div>
      </div>

      {loading && (
        <p className="mono" style={{ color: 'var(--text-3)', textAlign: 'center', marginTop: 40 }}>
          Loading marketplace…
        </p>
      )}

      {err && (
        <div className="card" style={{
          borderColor: 'rgba(255,77,94,0.5)', background: 'var(--red-soft)',
          padding: 14, borderRadius: 10
        }}>
          <div className="mono" style={{ fontSize: 12, color: '#ff8a9c' }}>{err}</div>
        </div>
      )}

      {!loading && filtered.length === 0 && !err && (
        <div style={{
          background: 'var(--bg-1)',
          border: '1px dashed rgba(255,255,255,0.08)',
          borderRadius: 12, padding: 32, textAlign: 'center', marginTop: 8
        }}>
          <div style={{ fontFamily: 'var(--font-display)', fontSize: 22, color: 'var(--text)', marginBottom: 6 }}>
            No listings match.
          </div>
          <p style={{ color: 'var(--text-3)', fontSize: 14, marginBottom: 18 }}>
            Try widening your filters — or be the first to list.
          </p>
          <button className="btn btn-primary btn-xl" onClick={() => onNav('/list')}>List your action</button>
        </div>
      )}

      {!loading && filtered.length > 0 && (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
          {filtered.map(l => (
            <ListingCard
              key={l.id}
              listing={l}
              rep={reps[l.player_handle.toLowerCase()]}
              onTapPlayer={() => onNav('/p/' + encodeURIComponent(l.player_handle))}
              onBack={() => window.PJ_MARKETPLACE_ACCEPT(l, onNav)}
            />
          ))}
        </div>
      )}

      <Footer />
    </div>
  );
}

function ListingCard({ listing, rep, onTapPlayer, onBack }) {
  const { fmtMoney, fmtPct } = window.PJ_UI;
  const remaining = Number(listing.pct_available) - (Number(listing.amount_taken) || 0);
  const lockedCount = rep ? (rep.locked_count || 0) : 0;
  const paidRate = rep ? rep.paid_rate : 1;
  const repBadge = lockedCount === 0
    ? { color: 'var(--text-3)', label: 'NEW' }
    : paidRate >= 0.95
      ? { color: 'var(--green)', label: lockedCount + ' LOCKED · ' + Math.round(paidRate * 100) + '% PAID' }
      : { color: '#FFB84D', label: lockedCount + ' LOCKED · ' + Math.round(paidRate * 100) + '% PAID' };

  return (
    <div style={{
      background: 'var(--bg-1)',
      border: '1px solid rgba(255,255,255,0.06)',
      borderRadius: 14,
      padding: 16,
      transition: 'all 180ms ease'
    }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 10 }}>
        <div style={{ minWidth: 0, flex: 1 }}>
          <button
            type="button"
            onClick={onTapPlayer}
            style={{
              all: 'unset', cursor: 'pointer',
              fontFamily: 'var(--font-display)', fontSize: 16, fontWeight: 700,
              color: 'var(--text)', letterSpacing: '-0.01em', marginBottom: 2,
              display: 'block'
            }}
          >
            @{listing.player_handle}
          </button>
          <div className="mono" style={{
            fontSize: 9, letterSpacing: '0.14em', textTransform: 'uppercase',
            color: repBadge.color
          }}>{repBadge.label}</div>
        </div>
        <div style={{ textAlign: 'right', flexShrink: 0, marginLeft: 12 }}>
          <div style={{
            fontFamily: 'var(--font-display)', fontSize: 22, fontWeight: 800,
            color: 'var(--green)', textShadow: '0 0 18px var(--green-glow-2)',
            letterSpacing: '-0.02em'
          }}>{remaining.toFixed(0)}%</div>
          <div className="mono" style={{
            fontSize: 9, letterSpacing: '0.14em', textTransform: 'uppercase',
            color: 'var(--text-3)', marginTop: 1
          }}>available</div>
        </div>
      </div>

      <div style={{
        padding: '10px 12px', borderRadius: 8,
        background: 'rgba(255,255,255,0.02)',
        border: '1px solid rgba(255,255,255,0.04)',
        marginBottom: 12
      }}>
        <div style={{ fontSize: 14, color: 'var(--text)', fontWeight: 600, marginBottom: 4 }}>
          {listing.tournament_name}
        </div>
        <div className="mono" style={{
          fontSize: 11, letterSpacing: '0.08em',
          color: 'var(--text-3)', textTransform: 'uppercase'
        }}>
          {listing.buy_in ? fmtMoney(listing.buy_in) + ' BUY-IN' : 'BUY-IN TBD'} · {Number(listing.markup).toFixed(2)}X MARKUP
        </div>
      </div>

      {listing.notes && (
        <p style={{ fontSize: 13, color: 'var(--text-2)', marginBottom: 12, lineHeight: 1.4 }}>
          {listing.notes}
        </p>
      )}

      <button
        type="button"
        onClick={onBack}
        style={{
          all: 'unset', cursor: 'pointer', display: 'block', textAlign: 'center',
          width: '100%', padding: '12px 16px', borderRadius: 10,
          background: 'linear-gradient(180deg, #E8ECEF 0%, #B8BFC8 55%, #8A929C 100%)',
          color: '#0B0E11',
          fontFamily: 'var(--font-display)', fontSize: 14, fontWeight: 700,
          letterSpacing: '-0.01em',
          boxShadow: 'inset 0 1px 0 rgba(255,255,255,0.65), 0 0 0 1px #2A323C, 0 0 18px rgba(0,224,138,0.25), 0 6px 18px rgba(0,0,0,0.5)'
        }}
      >
        Back this player →
      </button>
    </div>
  );
}

// Helper that pops the "how much do you want?" prompt + creates the swap.
// Exposed on window so the card can call it without prop-drilling deep.
window.PJ_MARKETPLACE_ACCEPT = async function (listing, onNav) {
  const handle = (window.pjGetHandle() || '').trim();
  let backerHandle = handle;
  if (!backerHandle) {
    backerHandle = window.prompt('Your handle (the backer):', '');
    if (!backerHandle) return;
    backerHandle = backerHandle.trim();
    window.pjSetHandle(backerHandle);
  }
  const remaining = Number(listing.pct_available) - (Number(listing.amount_taken) || 0);
  const ask = window.prompt(
    `How much of @${listing.player_handle}'s action do you want?\n(Up to ${remaining}% available)`,
    String(remaining)
  );
  if (!ask) return;
  const takePct = Math.max(0, Math.min(remaining, Number(ask) || 0));
  if (takePct <= 0) { alert('Enter a percentage greater than 0.'); return; }
  try {
    const swap = await window.pjAcceptListing(listing.id, backerHandle, takePct);
    // Send the backer to the swap detail screen as the acceptor — same
    // flow as the existing peer-to-peer lock. The player (originator)
    // gets the swap on their /swaps screen and locks via QR.
    onNav('/s/' + swap.id + '?role=acceptor&token=' + swap.secret_token);
  } catch (e) {
    alert('Could not back this listing: ' + (e.message || e));
  }
};

window.BrowseScreen = BrowseScreen;
