105 lines
3.6 KiB
TypeScript
105 lines
3.6 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server";
|
|
import { db } from "@/lib/db";
|
|
import { getApiUser } from "@/lib/apiAuth";
|
|
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 apiUser = await getApiUser(req);
|
|
if (!apiUser || apiUser.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 });
|
|
}
|