import axios from "axios"; import { getGame, createGame } from "../state/game.js"; import { getUser } from "../state/connection.js"; const API_URL = "http://localhost:8000/api/v1"; async function saveGameResult(gameId, result, token) { try { const payload = { status: "Ended", is_draw: result.isDraw, total_time: result.totalTime, player1_points: result.player1_points, player2_points: result.player2_points, }; if (!result.isDraw && result.winnerId) { payload.winner_user_id = result.winnerId; payload.loser_user_id = result.loserId; } await axios.put(`${API_URL}/games/${gameId}`, payload, { headers: { Authorization: token }, }); console.log(`[DB] Game ${gameId} saved.`); } catch (error) { console.error(`[DB Error] Game ${gameId}:`, error.message); } } const handleGameMove = (io, gameId, userId, cardId) => { const game = getGame(gameId); if (!game) return; const result = game.playCard(userId, cardId); if (result.error) { console.log(`[Game Error] ${result.error}`); return; } const roomName = `game_${gameId}`; const socketsInRoom = io.sockets.adapter.rooms.get(roomName); if (socketsInRoom) { for (const socketId of socketsInRoom) { const s = io.sockets.sockets.get(socketId); const u = getUser(socketId); if (u && game.players[u.id]) { s.emit("game-state", game.getStateForPlayer(u.id)); } } } if (result.action === "trick_resolved") { io.to(roomName).emit("trick-end", result.trickResult); } if (result.action === "game_ended") { io.to(roomName).emit("game-over", { winnerId: result.winnerId, isDraw: result.isDraw, p1Points: result.player1_points, p2Points: result.player2_points, }); let tokenToUse = null; const playerIds = Object.keys(game.players); for (const pid of playerIds) { if (game.players[pid] && game.players[pid].token) { tokenToUse = game.players[pid].token; break; } } if (tokenToUse) { saveGameResult(gameId, result, tokenToUse); console.log(`[DB] Jogo salvo usando o token de um dos jogadores.`); } else { console.error( `[DB Error] CRÍTICO: Nenhum jogador tem token. O jogo ${gameId} não foi salvo.` ); } } if (result.action === "next_turn" || result.action === "trick_resolved") { game.startTurnTimer((timeoutUserId, timeoutCardId) => { handleGameMove(io, gameId, timeoutUserId, timeoutCardId); }); if (socketsInRoom) { for (const socketId of socketsInRoom) { const s = io.sockets.sockets.get(socketId); const u = getUser(socketId); if (u && game.players[u.id]) s.emit("game-state", game.getStateForPlayer(u.id)); } } } }; export default (io, socket) => { socket.on("join-game", async ({ gameId }) => { const user = getUser(socket.id); if (!user) { socket.emit("error", { message: "Not authenticated." }); return; } let game = getGame(gameId); if (!game) { try { const token = socket.handshake.auth.token; const response = await axios.get(`${API_URL}/games/${gameId}`, { headers: { Authorization: token }, }); const gameData = response.data.data || response.data; console.log( `[Join Debug] API Data recebida para Jogo ${gameId}:`, gameData ? "OK" : "NULL" ); if ( gameData.player2_user_id == 1 && user.id != gameData.player1_user_id ) { try { console.log( `[API Sync] A oficializar User ${user.id} como Player 2 na BD...` ); await axios.post( `${API_URL}/games/${gameId}/join`, {}, { headers: { Authorization: token }, } ); console.log(`[API Sync] Sucesso! O jogo passou a 'Playing' na BD.`); gameData.player2_user_id = user.id; gameData.player2 = { name: user.name }; gameData.status = "Playing"; } catch (joinError) { console.error( `[API Sync Error] Falha ao fazer join na BD:`, joinError.message ); } } if (gameData.status === "Ended") { socket.emit("error", { message: "Game already finished." }); return; } if ( gameData.player1_user_id != user.id && gameData.player2_user_id != user.id && gameData.player2_user_id !== 1 ) { socket.emit("error", { message: "You are not in this game." }); return; } const p1Name = gameData.player1?.name || "Player 1"; const p2Name = gameData.player2?.name || "Player 2"; const type = gameData.type == "9" ? 9 : 3; game = createGame( gameId, type, { id: gameData.player1_user_id, name: p1Name }, { id: gameData.player2_user_id, name: p2Name } ); console.log( `[Join Debug] Jogo criado?`, game ? "SIM" : "NÃO (Undefined)" ); } catch (error) { if (error.response) { console.error(`[Join Error] Status: ${error.response.status}`); console.error(`[Join Error] Data:`, error.response.data); } else { console.error(`[Join Error] Message:`, error.message); } socket.emit("error", { message: "Failed to join game." }); return; } } const GHOST_ID = 1; if (game && game.players) { if (game.players[user.id]) { game.players[user.id].token = socket.handshake.auth.token; } if (!game.players[user.id] && game.players[GHOST_ID]) { console.log(`[Ghost Swap] User ${user.name} substituiu o Fantasma.`); delete game.players[GHOST_ID]; game.players[user.id] = { id: user.id, name: user.name, hand: [], points: 0, tricks: 0, token: socket.handshake.auth.token, }; const token = socket.handshake.auth.token; axios .post( `${API_URL}/games/${gameId}/join`, {}, { headers: { Authorization: token }, } ) .then(() => console.log(`[API Sync] Sucesso! BD atualizada para 'Playing'.`) ) .catch((err) => console.error(`[API Sync Error]`, err.message)); } } socket.join(`game_${gameId}`); if (game && game.players[user.id]) { socket.emit("game-state", game.getStateForPlayer(user.id)); console.log(`--> Estado enviado para User ${user.id}`); game.players[user.id].token = socket.handshake.auth.token; if (!game.timer && game.status === "playing") { game.startTurnTimer((uId, cId) => handleGameMove(io, gameId, uId, cId)); } socket.emit("game-state", game.getStateForPlayer(user.id)); } else { socket.emit("error", { message: "Error joining game state." }); } }); socket.on("play-card", ({ gameId, cardId }) => { const user = getUser(socket.id); const game = getGame(gameId); if (!game || !user) return; const result = game.playCard(user.id, cardId); if (result.error) { socket.emit("game-error", { message: result.error }); return; } handleGameMove(io, gameId, user.id, cardId); const roomName = `game_${gameId}`; const socketsInRoom = io.sockets.adapter.rooms.get(roomName); if (socketsInRoom) { for (const socketId of socketsInRoom) { const s = io.sockets.sockets.get(socketId); const u = getUser(socketId); if (u && game.players[u.id]) { s.emit("game-state", game.getStateForPlayer(u.id)); } } } if (result.action === "trick_resolved") { io.to(roomName).emit("trick-end", result.trickResult); } if (result.action === "game_ended") { io.to(roomName).emit("game-over", { winnerId: result.winnerId, isDraw: result.isDraw, p1Points: result.player1_points, p2Points: result.player2_points, }); saveGameResult(gameId, result, socket.handshake.auth.token); } }); };