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;
});
