// One proof-feed message per purchase (Marty, 2026-09-25).
//
// The feed used to post each tier payout on its own line and, in payouts mode, never said who
// bought what. Marty: "I see the level 1 payout, I see a level 2 payout, but I don't see who
// purchased something and what they bought." So: the buyer and the package first, then the
// level payouts under it, then any pass-ups, as ONE message. It composes from every event of
// the transaction, which is why the caller triggers it on AdminPaid, the last event the contract
// emits for a purchase: by then Purchase, TierPaid and PassedUp of that tx are all indexed.
//
// Pure: events in, HTML string out. Tested against real index rows before it shipped.
'use strict';
const PCT = { 1: 50, 2: 20, 3: 10 };
function usd(cents) { return ('$' + (cents / 100).toFixed(2)).replace(/\.00$/, ''); }
// txEvents: every indexed event with this tx. who(id) -> "#12 @name". weiToPol(wei) -> "1.23".
// Returns null when there is no Purchase in the tx (not a package purchase) or when
// `requirePayout` is set and no member was paid (a root or unsponsored buyer: nothing to prove).
function compose(txEvents, who, weiToPol, opts) {
opts = opts || {};
const pur = txEvents.find(e => e.type === 'Purchase');
if (!pur) return null;
const tiers = txEvents.filter(e => e.type === 'TierPaid').sort((a, b) => (a.tier || 0) - (b.tier || 0) || (a.li || 0) - (b.li || 0));
if (opts.requirePayout && !tiers.length) return null;
const lines = ['\u{1F9FE} ' + who(pur.buyerId) + ' bought a ' + usd(pur.priceCents) + ' package'];
for (const t of tiers) {
const pct = PCT[t.tier];
const about = pct ? ' (' + usd(Math.round(pur.priceCents * pct / 100)) + ')' : '';
lines.push('\u{1F4B8} Level ' + t.tier + ': ' + weiToPol(t.amountWei) + ' POL' + about + ' → ' + who(t.recipientId)
+ (t.hops > 0 ? ' (passed up ' + t.hops + ')' : ''));
}
if (!tiers.length) lines.push('No member payout on this one: the buyer has nobody above them to pay.');
const passed = txEvents.filter(e => e.type === 'PassedUp');
for (const p of passed) if (p.skippedId) lines.push('⏭ Level ' + (p.tier || '?') + ' skipped ' + who(p.skippedId) + ' (not yet qualified)');
return lines.join('\n');
}
module.exports = { compose };