import { usePrisma } from "../../../../utils/prisma"; interface MemoryCard { id: number; emoji: string; matchedBy: "X" | "O" | null; } interface MemoryState { cards: MemoryCard[]; flipped: number[]; scores: { X: number; O: number }; mismatchRevealed: boolean; } export default defineEventHandler(async (event) => { const user = await requireUser(event); const id = getRouterParam(event, "id"); if (!id) throw createError({ statusCode: 400, message: "id fehlt" }); const body = await readBody(event) as { cardIndex: number }; const { cardIndex } = body; if (typeof cardIndex !== "number" || cardIndex < 0 || cardIndex > 15) { throw createError({ statusCode: 400, message: "Ungültiger Zug" }); } const db = usePrisma(); const challenge = await db.gameChallenge.findUnique({ where: { id } }); if (!challenge) throw createError({ statusCode: 404, message: "Challenge nicht gefunden" }); if (challenge.status !== "ACTIVE") throw createError({ statusCode: 409, message: "Spiel nicht aktiv" }); if (challenge.gameType !== "memory") throw createError({ statusCode: 400, message: "Kein Memory-Spiel" }); const isChallenger = user.id === challenge.challengerId; const isOpponent = user.id === challenge.opponentId; if (!isChallenger && !isOpponent) throw createError({ statusCode: 403, message: "Nicht autorisiert" }); const myMark: "X" | "O" = isChallenger ? "X" : "O"; if (challenge.currentTurn !== myMark) throw createError({ statusCode: 409, message: "Nicht dein Zug" }); const state = JSON.parse(JSON.stringify(challenge.memoryState)) as MemoryState; const card = state.cards[cardIndex]; if (!card) throw createError({ statusCode: 400, message: "Ungültige Karte" }); if (card.matchedBy !== null) throw createError({ statusCode: 409, message: "Karte bereits gefunden" }); let newStatus = challenge.status as string; let newWinner: string | null = challenge.winner; let nextTurn: string = myMark; // Mismatch pending: player must click one of their 2 revealed cards to hide them if (state.mismatchRevealed) { if (!state.flipped.includes(cardIndex)) { throw createError({ statusCode: 409, message: "Decke zuerst deine aufgedeckten Karten zu" }); } // Hide both cards and switch turn state.flipped = []; state.mismatchRevealed = false; nextTurn = myMark === "X" ? "O" : "X"; } else { if (state.flipped.includes(cardIndex)) { throw createError({ statusCode: 409, message: "Karte bereits aufgedeckt" }); } if (state.flipped.length === 0) { state.flipped = [cardIndex]; } else { // Second flip const firstId = state.flipped[0]!; const firstCard = state.cards[firstId]!; state.flipped = [firstId, cardIndex]; if (firstCard.emoji === card.emoji) { // Match – mark both, clear flipped, stay on same turn state.cards[firstId]!.matchedBy = myMark; state.cards[cardIndex]!.matchedBy = myMark; state.scores[myMark]++; state.flipped = []; const totalPairs = state.cards.length / 2; const matchedPairs = state.cards.filter(c => c.matchedBy !== null).length / 2; if (matchedPairs === totalPairs) { newStatus = "FINISHED"; const { X, O } = state.scores; newWinner = X > O ? "X" : O > X ? "O" : "draw"; } // nextTurn stays as myMark (scorer goes again) } else { // Mismatch – show cards, stay on same turn until player hides them state.mismatchRevealed = true; // nextTurn stays as myMark } } } const updated = await db.gameChallenge.update({ where: { id }, data: { memoryState: state as any, currentTurn: nextTurn, ...(newStatus !== challenge.status && { status: newStatus as any }), ...(newWinner !== challenge.winner && { winner: newWinner }), }, }); if (newStatus === "FINISHED" && challenge.opponentId && challenge.opponentName) { const challengerId = challenge.challengerId; const opponentId = challenge.opponentId; const challengerName = challenge.challengerName; const opponentName = challenge.opponentName; if (newWinner === "draw") { await Promise.all([ db.gameScore.upsert({ where: { userId: challengerId }, update: { draws: { increment: 1 }, points: { increment: 1 }, playerName: challengerName }, create: { userId: challengerId, playerName: challengerName, draws: 1, points: 1 }, }), db.gameScore.upsert({ where: { userId: opponentId }, update: { draws: { increment: 1 }, points: { increment: 1 }, playerName: opponentName }, create: { userId: opponentId, playerName: opponentName, draws: 1, points: 1 }, }), ]); } else { const winnerId = newWinner === "X" ? challengerId : opponentId; const loserId = newWinner === "X" ? opponentId : challengerId; const winnerName = newWinner === "X" ? challengerName : opponentName; const loserName = newWinner === "X" ? opponentName : challengerName; await Promise.all([ db.gameScore.upsert({ where: { userId: winnerId }, update: { wins: { increment: 1 }, points: { increment: 3 }, playerName: winnerName }, create: { userId: winnerId, playerName: winnerName, wins: 1, points: 3 }, }), db.gameScore.upsert({ where: { userId: loserId }, update: { losses: { increment: 1 }, playerName: loserName }, create: { userId: loserId, playerName: loserName, losses: 1 }, }), ]); } if (challenge.postId) { await db.communityPost.delete({ where: { id: challenge.postId } }).catch(() => {}); } } return updated; });