Files
football-next/app/api/admin/quiz/[id]/lottery/route.ts
2026-05-03 17:01:46 +03:30

106 lines
3.6 KiB
TypeScript

import { NextRequest, NextResponse } from "next/server";
import { db } from "@/lib/db";
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth";
import { CARD_TIER_LABELS, resolveQuizRewardTier } from "@/lib/cardTier";
function shuffleArray<T>(items: T[]) {
return [...items].sort(() => Math.random() - 0.5);
}
// POST /api/admin/quiz/[id]/lottery - run reward distribution for a quiz
export async function POST(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
const session = await getServerSession(authOptions);
if (!session || (session.user as any).role !== "ADMIN") {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
const { id } = await params;
const quiz = await db.dailyQuiz.findUnique({
where: { id },
include: { questions: true },
});
if (!quiz) return NextResponse.json({ error: "Quiz not found" }, { status: 404 });
if (quiz.isProcessed) {
return NextResponse.json({ error: "قرعه کشی قبلا انجام شده" }, { status: 400 });
}
const submissions = await db.quizSubmission.findMany({
where: { quizId: id },
include: { user: true },
});
const tierLimits = {
GOLD: quiz.goldWinnersCount,
SILVER: quiz.silverWinnersCount,
BRONZE: quiz.bronzeWinnersCount,
} as const;
const candidatesByTier = {
GOLD: submissions.filter((submission) => resolveQuizRewardTier(quiz, submission.correctAnswers) === "GOLD"),
SILVER: submissions.filter((submission) => resolveQuizRewardTier(quiz, submission.correctAnswers) === "SILVER"),
BRONZE: submissions.filter((submission) => resolveQuizRewardTier(quiz, submission.correctAnswers) === "BRONZE"),
};
const rewardQueue = (["GOLD", "SILVER", "BRONZE"] as const).flatMap((cardTier) =>
shuffleArray(candidatesByTier[cardTier])
.slice(0, Math.max(tierLimits[cardTier], 0))
.map((submission) => ({ submission, cardTier }))
);
if (rewardQueue.length === 0) {
await db.dailyQuiz.update({ where: { id }, data: { isProcessed: true } });
return NextResponse.json({ winners: [], message: "هیچ شرکت کننده ای واجد دریافت کارت نبود" });
}
const players = await db.player.findMany({
where: {
isActive: true,
cardTier: { in: ["GOLD", "SILVER", "BRONZE"] },
},
include: { country: true },
});
const playersByTier = {
GOLD: players.filter((player) => player.cardTier === "GOLD"),
SILVER: players.filter((player) => player.cardTier === "SILVER"),
BRONZE: players.filter((player) => player.cardTier === "BRONZE"),
};
for (const tier of ["GOLD", "SILVER", "BRONZE"] as const) {
if (rewardQueue.some((item) => item.cardTier === tier) && playersByTier[tier].length === 0) {
return NextResponse.json(
{ error: `برای کارت ${CARD_TIER_LABELS[tier]} هیچ بازیکن فعالی تعریف نشده است` },
{ status: 400 }
);
}
}
const createdCards = await db.$transaction(
rewardQueue.map(({ submission, cardTier }) => {
const tierPlayers = playersByTier[cardTier];
const randomPlayer = tierPlayers[Math.floor(Math.random() * tierPlayers.length)];
return db.goldenCard.create({
data: {
userId: submission.userId,
quizId: id,
playerId: randomPlayer.id,
cardTier,
status: "SEALED",
},
include: {
user: { select: { id: true, name: true, email: true } },
player: { include: { country: true } },
},
});
})
);
await db.dailyQuiz.update({ where: { id }, data: { isProcessed: true } });
return NextResponse.json({ winners: createdCards });
}