import { useCallback, useEffect, useState } from 'react'; import { getGame, makeGameMove, type GameRecord } from '@chat-app/shared/chat'; import { supabase } from '../lib/supabase'; export function useGame(gameId: string | null): { game: GameRecord | null; loading: boolean; error: string | null; makeMove: (move: object) => Promise; } { const [game, setGame] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { if (!gameId) { setGame(null); setLoading(false); setError(null); return; } let cancelled = false; void (async () => { try { setLoading(true); setError(null); const fresh = await getGame(supabase, gameId); if (!cancelled) { setGame(fresh); setLoading(false); } } catch (err) { if (!cancelled) { setLoading(false); setError(err instanceof Error ? err.message : 'failed to load game'); } } })(); const channel = supabase .channel('game:' + gameId) .on( 'postgres_changes', { event: 'UPDATE', schema: 'public', table: 'conversation_games', filter: 'id=eq.' + gameId, }, () => { void getGame(supabase, gameId) .then((fresh) => { if (fresh) setGame(fresh); }) .catch((err) => { console.warn('game realtime refetch failed', err); }); }, ) .subscribe(); return () => { cancelled = true; void supabase.removeChannel(channel); }; }, [gameId]); const makeMove = useCallback(async (move: object) => { if (!gameId) return; try { await makeGameMove(supabase, { gameId, move }); } catch (err) { setError(err instanceof Error ? err.message : 'move failed'); throw err; } }, [gameId]); return { game, loading, error, makeMove }; }