/* global React, sbx */
// Referrals (Hub phase 4) — attribution + coupons.
//
// The ?via=@handle param on share links (pools, seats) is stashed in
// localStorage by pools-data.jsx BEFORE auth. This file turns that stash
// into a referral: the Welcome screen shows the "$10 off" banner from it,
// and once a session + profile exist the App calls claimPendingReferral()
// — best-effort and silent (an ineligible claim never blocks anything).
//
// Coupons are credit_ledger rows (simulated pre-Stripe): $10 to the
// friend at signup, $5 to the referrer after the friend's first
// completed + dual-confirmed match (referrals.sql cron sweep).

const REF_VIA_KEY = 'spp_ref_via';       // written by pools-data.jsx at boot (link param)
const REF_TYPED_KEY = 'spp_ref_typed';   // code typed in the sign-up step — WINS over the link

// Peek at the stashed attribution (7-day staleness) without clearing it.
function getRefVia() {
  try {
    const raw = JSON.parse(localStorage.getItem(REF_VIA_KEY) || 'null');
    if (!raw || !raw.via) return null;
    if (Date.now() - (raw.at || 0) > 7 * 86400000) return null;
    return String(raw.via).replace(/^@/, '');
  } catch (_) { return null; }
}

function clearRefVia() {
  try { localStorage.removeItem(REF_VIA_KEY); } catch (_) { /* noop */ }
}

// Normalize a typed code the same way the server does: strip junk,
// uppercase, ensure the SBX- prefix.
function normalizeReferralCode(code) {
  const raw = String(code || '').replace(/[^a-zA-Z0-9]/g, '').toUpperCase().replace(/^SBX/, '');
  return raw ? `SBX-${raw}` : '';
}

// Anonymous validity check (anon-callable RPC — sign-up runs pre-auth).
// → true | false | null (RPC unavailable — treat as unknown, don't block).
async function lookupReferralCode(code) {
  const normalized = normalizeReferralCode(code);
  if (!normalized) return false;
  try {
    const { data, error } = await sbx.rpc('lookup_referral_code', { p_code: normalized });
    if (error) return null;
    return !!data;
  } catch (_) { return null; }
}

// Stash the code typed at sign-up (claimed after the profile exists).
function setTypedReferralCode(code) {
  try {
    const normalized = normalizeReferralCode(code);
    if (normalized) localStorage.setItem(REF_TYPED_KEY, JSON.stringify({ code: normalized, at: Date.now() }));
  } catch (_) { /* private mode */ }
}
function getTypedReferralCode() {
  try {
    const raw = JSON.parse(localStorage.getItem(REF_TYPED_KEY) || 'null');
    if (!raw || !raw.code) return null;
    if (Date.now() - (raw.at || 0) > 7 * 86400000) return null;
    return raw.code;
  } catch (_) { return null; }
}
function clearTypedReferralCode() {
  try { localStorage.removeItem(REF_TYPED_KEY); } catch (_) { /* noop */ }
}

// Claim the stashed referral for the signed-in user. A code TYPED at
// sign-up wins over a link stash (explicit beats implicit — decided).
// Silent by design: any ineligibility (already claimed, not a new
// account, self-referral, RPC not migrated) just clears/keeps the
// stashes without surfacing. → { referrerHandle } on success, null otherwise.
async function claimPendingReferral() {
  const typed = getTypedReferralCode();
  const via = getRefVia();
  const attribution = typed || via;
  if (!attribution) return null;
  try {
    const { data, error } = await sbx.rpc('claim_referral', {
      p_handle: attribution, p_source: typed ? 'code' : 'link', p_source_ref: {},
    });
    if (error) {
      // Permanent ineligibilities → drop the stashes; transient (RPC not
      // migrated yet) → keep them for a later session.
      const msg = (error.message || '').toLowerCase();
      if (msg.includes('already') || msg.includes('self') || msg.includes('not found')) {
        clearTypedReferralCode(); clearRefVia();
      }
      return null;
    }
    clearTypedReferralCode(); clearRefVia();
    return { referrerHandle: data && data.referrer_handle };
  } catch (_) { return null; }
}

// Active promo coupons for the signed-in user (display-only pre-Stripe).
// → [{ amountCents, expiresAt, referrerHandle }], newest first.
function useMyCoupons(userId) {
  const [coupons, setCoupons] = React.useState([]);
  React.useEffect(() => {
    if (!userId) { setCoupons([]); return undefined; }
    let on = true;
    (async () => {
      const { data, error } = await sbx.from('credit_ledger')
        .select('amount_cents, expires_at, meta, created_at')
        .eq('user_id', userId).eq('kind', 'promo_coupon').gt('amount_cents', 0)
        .gt('expires_at', new Date().toISOString())
        .order('created_at', { ascending: false });
      if (!on || error) return;
      setCoupons((data || []).map(r => ({
        amountCents: r.amount_cents,
        expiresAt: r.expires_at,
        referrerHandle: (r.meta && r.meta.referrer_handle) || null,
      })));
    })();
    return () => { on = false; };
  }, [userId]);
  return coupons;
}

Object.assign(window, {
  getRefVia, clearRefVia, claimPendingReferral, useMyCoupons,
  normalizeReferralCode, lookupReferralCode, setTypedReferralCode, getTypedReferralCode, clearTypedReferralCode,
});
