/* global React, sbx */
// Group bookings (Hub phase 5) — data layer.
//
// A booker locks in their 3 people (or leaves seats open / invites by
// link), a WINDOW — never a slot — and teams. Nothing is held during the
// 3h accept clock; the pod locks (slot assigned + everyone charged, once)
// only when all four are in. All writes go through the groups.sql RPCs.

async function createGroupBooking({ courseId, dateStr, startMin, endMin, seats }) {
  // seats: [{ team:'A'|'B', mode:'user'|'open'|'link', userId? }] — 3 entries.
  const payload = (seats || []).map(s => ({ team: s.team, mode: s.mode, user_id: s.userId || null }));
  const { data, error } = await sbx.rpc('create_group_booking', {
    p_course: courseId, p_date: dateStr, p_start_min: startMin, p_end_min: endMin,
    p_seats: payload,
  });
  if (error) throw new Error(error.message || 'Could not create the group booking.');
  return data; // group id
}

async function respondGroupSeat(seatId, accept) {
  const { error } = await sbx.rpc('respond_group_seat', { p_seat: seatId, p_accept: !!accept });
  if (error) throw new Error(error.message || 'Could not respond to the invite.');
}

async function claimGroupSeat(token) {
  const { data, error } = await sbx.rpc('claim_group_seat', { p_token: token });
  if (error) throw new Error(error.message || 'Could not claim the seat.');
  return data; // group id
}

async function shuffleGroupTeams(groupId) {
  const { error } = await sbx.rpc('shuffle_group_teams', { p_group: groupId });
  if (error) throw new Error(error.message || 'Could not shuffle teams.');
}

async function cancelGroupBooking(groupId) {
  const { error } = await sbx.rpc('cancel_group_booking', { p_group: groupId });
  if (error) throw new Error(error.message || 'Could not cancel the group.');
}

async function getSeatInvite(token) {
  const { data, error } = await sbx.rpc('get_seat_invite', { p_token: token });
  if (error) return null;
  return data;
}

// My PENDING groups (as booker or seated player), seats + profiles
// resolved. Locked groups already surface as bookings/assignments, so
// the pending card disappears on lock. Realtime + 30s fallback poll.
function useMyGroups(userId) {
  const [groups, setGroups] = React.useState(null);

  const load = React.useCallback(async () => {
    if (!userId) { setGroups([]); return; }
    const { data, error } = await sbx.from('group_bookings')
      .select(`
        *,
        course:courses!group_bookings_course_id_fkey(id, short_name, city),
        seats:group_seats(id, team, user_id, status, invite_token, created_at)
      `)
      .eq('status', 'pending')
      .order('created_at', { ascending: false });
    if (error) { setGroups([]); return; } // tables not migrated yet
    const rows = (data || []).filter(g =>
      g.booker_id === userId || (g.seats || []).some(s => s.user_id === userId));

    // Resolve seat profiles in one query.
    const ids = [...new Set(rows.flatMap(g => (g.seats || []).map(s => s.user_id)).filter(Boolean))];
    let byId = {};
    if (ids.length) {
      const { data: profs } = await sbx.from('profiles')
        .select('id, handle, first_name, last_name, avatar_url, sbx').in('id', ids);
      (profs || []).forEach(p => { byId[p.id] = p; });
    }
    rows.forEach(g => {
      (g.seats || []).forEach(s => { s.profile = s.user_id ? byId[s.user_id] : null; });
      g.seats.sort((a, b) => (a.team === b.team ? a.created_at.localeCompare(b.created_at) : a.team.localeCompare(b.team)));
    });
    setGroups(rows);
  }, [userId]);

  React.useEffect(() => { load(); }, [load]);

  const channelName = React.useRef(`groups-${Math.random().toString(36).slice(2, 10)}`).current;
  React.useEffect(() => {
    if (!userId) return undefined;
    const ch = sbx.channel(channelName)
      .on('postgres_changes', { event: '*', schema: 'public', table: 'group_bookings' }, () => load())
      .on('postgres_changes', { event: '*', schema: 'public', table: 'group_seats' }, () => load())
      .subscribe();
    const iv = setInterval(load, 30000);
    return () => { sbx.removeChannel(ch); clearInterval(iv); };
  }, [userId, channelName, load]);

  return [groups, load];
}

function seatShareUrl(token, viaHandle) {
  const via = viaHandle ? `&via=${encodeURIComponent(String(viaHandle).replace(/^@/, ''))}` : '';
  return `https://sbx.golf/?seat=${token}${via}`;
}

async function shareSeatLink({ url, courseName, dayLabel }) {
  const text = `You're invited to a 2v2 group round at ${courseName} (${dayLabel}). Grab your seat:`;
  try {
    if (navigator.share) { await navigator.share({ title: 'Sandbox Pitch & Putt', text, url }); return 'shared'; }
  } catch (e) { if (e && e.name === 'AbortError') return null; }
  try { await navigator.clipboard.writeText(`${text} ${url}`); return 'copied'; } catch (_) { return null; }
}

Object.assign(window, {
  createGroupBooking, respondGroupSeat, claimGroupSeat, shuffleGroupTeams,
  cancelGroupBooking, getSeatInvite, useMyGroups, seatShareUrl, shareSeatLink,
});
