import type { ServerGameStateMessage, ServerMessageTyped as ServerMessage, Team, } from './protocol' const WS_URL = import.meta.env.VITE_WS_URL function resolveWsUrl(): string { if (WS_URL) return WS_URL const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:' return `${protocol}//${window.location.hostname}:3000/ws` } export interface NetCallbacks { onJoined: (room: string, team: Team) => void onWaiting: (message: string) => void onGameState: (msg: ServerGameStateMessage) => void onTrajectory: (path: [number, number, number][]) => void onEndScored: (end: number, points: number, scoringTeam: Team | null) => void onGameOver: (scores: number[], winner: Team | null) => void onError: (message: string) => void onClose: () => void } let socket: WebSocket | null = null export function connect(room: string, team: Team | null, callbacks: NetCallbacks): void { if (socket) return const teamParam = team ? `&team=${encodeURIComponent(team)}` : '' const url = `${resolveWsUrl()}?room=${encodeURIComponent(room)}${teamParam}` const ws = new WebSocket(url) ws.onopen = () => { socket = ws } ws.onmessage = (event) => { try { const msg = JSON.parse(event.data) as ServerMessage if (!msg || typeof msg.type !== 'string') return switch (msg.type) { case 'joined': callbacks.onJoined(msg.room, msg.team) break case 'waiting': callbacks.onWaiting(msg.message) break case 'game_state': callbacks.onGameState(msg) break case 'trajectory': callbacks.onTrajectory(msg.path) break case 'end_scored': callbacks.onEndScored(msg.end, msg.points, msg.scoring_team ?? null) break case 'game_over': callbacks.onGameOver(msg.scores, msg.winner) break case 'error': callbacks.onError(msg.message) break } } catch (err) { console.error('Failed to parse server message', err) } } ws.onclose = () => { socket = null callbacks.onClose() } ws.onerror = () => {} } export function sendThrow(broomX: number, broomY: number, weight: number, curl: number, friction: number): void { if (!socket || socket.readyState !== WebSocket.OPEN) return socket.send(JSON.stringify({ type: 'throw', broom_x: broomX, broom_y: broomY, weight, curl, friction })) }