/* global React, sbx */
// Match pools (Hub phase 3) — demand made visible.
//
// Hooks over the pool_blocks() RPC (pools.sql): per-course/date clock-hour
// aggregates of the window waitlist. Aggregates only — identities never
// leave the server. Plus the share-a-pool link plumbing: every share URL
// carries the sharer's handle (?via=), which doubles as the referral
// attribution channel (consumed in the referrals phase).
//
// Deep links: sbx.golf/?pool=<courseId>.<YYYY-MM-DD>.<blockHour>&via=@handle
// are captured at boot (before auth), stashed in localStorage, and consumed
// by the App once signed in — so the link survives the login/signup flow.

const POOL_DL_LS = 'spp_deeplink_pool';
const SEAT_DL_LS = 'spp_deeplink_seat';
const REF_VIA_LS = 'spp_ref_via';

// Runs at script load: capture ?pool= / ?seat= / ?via= params, stash,
// clean the URL. (?seat= is a group-booking seat-invite token.)
(function consumePoolDeepLink() {
  try {
    const params = new URLSearchParams(window.location.search);
    const pool = params.get('pool');
    const seat = params.get('seat');
    const via = params.get('via');
    if (via) localStorage.setItem(REF_VIA_LS, JSON.stringify({ via, at: Date.now() }));
    if (pool) {
      const [courseId, dateStr, block] = pool.split('.');
      if (courseId && dateStr) {
        localStorage.setItem(POOL_DL_LS, JSON.stringify({
          courseId, dateStr, block: block != null ? Number(block) : null, at: Date.now(),
        }));
      }
    }
    if (seat) localStorage.setItem(SEAT_DL_LS, JSON.stringify({ token: seat, at: Date.now() }));
    if (pool || seat || via) {
      const clean = window.location.pathname + window.location.hash;
      window.history.replaceState({}, '', clean);
    }
  } catch (_) { /* malformed link — ignore */ }
})();

// Pop the stashed pool deep link (one-shot). Links older than a day stale out.
function takePoolDeepLink() {
  try {
    const raw = JSON.parse(localStorage.getItem(POOL_DL_LS) || 'null');
    if (!raw) return null;
    localStorage.removeItem(POOL_DL_LS);
    if (Date.now() - (raw.at || 0) > 86400000) return null;
    return raw;
  } catch (_) { return null; }
}

// Pop the stashed seat-invite token (one-shot, same staleness rule).
function takeSeatDeepLink() {
  try {
    const raw = JSON.parse(localStorage.getItem(SEAT_DL_LS) || 'null');
    if (!raw) return null;
    localStorage.removeItem(SEAT_DL_LS);
    if (Date.now() - (raw.at || 0) > 86400000) return null;
    return raw.token || null;
  } catch (_) { return null; }
}

// ─── Pool blocks for one course/date ──────────────────────────────────
// → [blocks, loading]; blocks = [{ blockHour, available, inBand,
// wouldComplete, fromPrice }]. Live: reloads on tee_waitlist realtime
// changes (pools.sql adds the table to the publication) + 60s tick as a
// fallback while the migration hasn't run.
function usePoolBlocks(courseId, dateStr) {
  const [blocks, setBlocks] = React.useState([]);
  const [loading, setLoading] = React.useState(true);

  const load = React.useCallback(async () => {
    if (!courseId || !dateStr) { setBlocks([]); setLoading(false); return; }
    const { data, error } = await sbx.rpc('pool_blocks', { p_course: courseId, p_date: dateStr });
    if (error) { setBlocks([]); setLoading(false); return; } // RPC not migrated yet
    setBlocks((data || []).map(r => ({
      blockHour: r.block_hour, available: r.available, inBand: r.in_band,
      wouldComplete: r.would_complete, fromPrice: r.from_price,
    })));
    setLoading(false);
  }, [courseId, dateStr]);

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

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

  return [blocks, loading, load];
}

// ─── Hot pools across nearby courses (Home module) ────────────────────
// Fans out pool_blocks over the closest courses for today + tomorrow,
// flattens, and ranks: hot ("1 more locks a match") first, then by
// available count, then soonest. → [pools, loading]; each item =
// { course, dateStr, dayLabel, blockHour, available, inBand, wouldComplete, fromPrice }.
function useHotPools(courses, maxCourses = 6, maxPools = 6) {
  const [pools, setPools] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const courseKey = (courses || []).slice(0, maxCourses).map(c => c.id).join(',');

  const load = React.useCallback(async () => {
    const cs = (courses || []).slice(0, maxCourses);
    if (!cs.length) { setPools([]); setLoading(false); return; }
    const p = (n) => String(n).padStart(2, '0');
    const fmt = (d) => `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}`;
    const today = new Date(); const tomorrow = new Date(); tomorrow.setDate(today.getDate() + 1);
    const days = [{ dateStr: fmt(today), dayLabel: 'Today' }, { dateStr: fmt(tomorrow), dayLabel: 'Tomorrow' }];

    const out = [];
    await Promise.all(cs.flatMap(course => days.map(async d => {
      const { data, error } = await sbx.rpc('pool_blocks', { p_course: course.id, p_date: d.dateStr });
      if (error) return;
      (data || []).forEach(r => out.push({
        course, dateStr: d.dateStr, dayLabel: d.dayLabel,
        blockHour: r.block_hour, available: r.available, inBand: r.in_band,
        wouldComplete: r.would_complete, fromPrice: r.from_price,
      }));
    })));

    out.sort((a, b) =>
      (b.wouldComplete - a.wouldComplete)
      || (b.available - a.available)
      || a.dateStr.localeCompare(b.dateStr)
      || (a.blockHour - b.blockHour));
    setPools(out.slice(0, maxPools));
    setLoading(false);
  }, [courseKey]); // eslint-disable-line react-hooks/exhaustive-deps

  React.useEffect(() => { load(); }, [load]);
  React.useEffect(() => {
    const iv = setInterval(load, 60000);
    return () => clearInterval(iv);
  }, [load]);

  return [pools, loading];
}

// ─── Share a pool ─────────────────────────────────────────────────────
const blockLabel = (h) => {
  const f = (hh) => new Date(2000, 0, 1, hh).toLocaleTimeString('en-US', { hour: 'numeric' });
  return `${f(h)}–${f(h + 1)}`;
};

function poolShareUrl({ courseId, dateStr, blockHour, viaHandle }) {
  const base = 'https://sbx.golf/';
  const via = viaHandle ? `&via=${encodeURIComponent(String(viaHandle).replace(/^@/, ''))}` : '';
  return `${base}?pool=${courseId}.${dateStr}.${blockHour}${via}`;
}

// Native share sheet with clipboard fallback. → 'shared' | 'copied' | null
async function sharePool({ courseName, dateStr, blockHour, available, url }) {
  const day = new Date(`${dateStr}T00:00:00`).toLocaleDateString('en-US', { weekday: 'long' });
  const text = `${blockLabel(blockHour)} at ${courseName} on ${day} — ${available} ${available === 1 ? 'golfer is' : 'golfers are'} in. Join the pool:`;
  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, {
  usePoolBlocks, useHotPools, poolShareUrl, sharePool, blockLabel, takePoolDeepLink, takeSeatDeepLink,
});
