import { NextRequest, NextResponse } from "next/server";
import { db } from "@/lib/db";
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth";
import { Prisma } from "@prisma/client";

async function requireAdmin() {
  const session = await getServerSession(authOptions);
  if (!session || (session.user as any).role !== "ADMIN") {
    return null;
  }
  return session;
}

function calculateResult(answers: number[], questions: Array<{ correctAnswer: number }>) {
  let correct = 0;
  questions.forEach((question, index) => {
    if (answers[index] === question.correctAnswer) {
      correct += 1;
    }
  });

  return {
    correct,
    score: questions.length > 0 ? Math.round((correct / questions.length) * 100) : 0,
  };
}

function validateTierConfig(input: {
  goldWinnersCount: number;
  silverWinnersCount: number;
  bronzeWinnersCount: number;
  goldMinCorrect: number | null;
  silverMinCorrect: number | null;
  bronzeMinCorrect: number | null;
}) {
  if (input.goldWinnersCount < 0 || input.silverWinnersCount < 0 || input.bronzeWinnersCount < 0) {
    return "Winner counts cannot be negative";
  }

  if (input.goldWinnersCount + input.silverWinnersCount + input.bronzeWinnersCount <= 0) {
    return "At least one winner must be configured";
  }

  if (input.goldWinnersCount > 0 && input.goldMinCorrect == null) {
    return "Gold minimum correct answers is required";
  }

  if (input.silverWinnersCount > 0 && input.silverMinCorrect == null) {
    return "Silver minimum correct answers is required";
  }

  if (input.bronzeWinnersCount > 0 && input.bronzeMinCorrect == null) {
    return "Bronze minimum correct answers is required";
  }

  return null;
}

export async function PUT(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
  try {
    const session = await requireAdmin();
    if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });

    const { id } = await params;
    const {
      date,
      windowStart,
      windowEnd,
      goldWinnersCount,
      silverWinnersCount,
      bronzeWinnersCount,
      goldMinCorrect,
      silverMinCorrect,
      bronzeMinCorrect,
      questions,
    } = await req.json();

    const parsedInput = {
      goldWinnersCount: Number(goldWinnersCount),
      silverWinnersCount: Number(silverWinnersCount),
      bronzeWinnersCount: Number(bronzeWinnersCount),
      goldMinCorrect: goldMinCorrect == null ? null : Number(goldMinCorrect),
      silverMinCorrect: silverMinCorrect == null ? null : Number(silverMinCorrect),
      bronzeMinCorrect: bronzeMinCorrect == null ? null : Number(bronzeMinCorrect),
    };

    const validationError = validateTierConfig(parsedInput);
    if (validationError) {
      return NextResponse.json({ error: validationError }, { status: 400 });
    }

    if (!Array.isArray(questions) || questions.length === 0) {
      return NextResponse.json({ error: "At least one question is required" }, { status: 400 });
    }

    const quiz = await db.dailyQuiz.findUnique({
      where: { id },
      include: {
        submissions: {
          select: { id: true, answers: true },
        },
      },
    });

    if (!quiz) return NextResponse.json({ error: "Quiz not found" }, { status: 404 });
    if (quiz.isProcessed) {
      return NextResponse.json({ error: "Quiz can no longer be edited after lottery processing" }, { status: 400 });
    }

    const normalizedQuestions = questions.map((q: any, index: number) => ({
      questionText: q.questionText,
      options: q.options,
      correctAnswer: Number(q.correctAnswer),
      order: index,
    }));

    const updatedQuiz = await db.$transaction(async (tx) => {
      await tx.quizQuestion.deleteMany({ where: { quizId: id } });

      const updated = await tx.dailyQuiz.update({
        where: { id },
        data: {
          date: new Date(`${date}T00:00:00.000Z`),
          windowStart: new Date(windowStart),
          windowEnd: new Date(windowEnd),
          goldWinnersCount: parsedInput.goldWinnersCount,
          silverWinnersCount: parsedInput.silverWinnersCount,
          bronzeWinnersCount: parsedInput.bronzeWinnersCount,
          goldMinCorrect: parsedInput.goldMinCorrect,
          silverMinCorrect: parsedInput.silverMinCorrect,
          bronzeMinCorrect: parsedInput.bronzeMinCorrect,
          questions: {
            create: normalizedQuestions,
          },
        },
        include: {
          questions: { orderBy: { order: "asc" } },
        },
      });

      for (const submission of quiz.submissions) {
        const result = calculateResult(submission.answers, normalizedQuestions);
        await tx.quizSubmission.update({
          where: { id: submission.id },
          data: {
            score: result.score,
            correctAnswers: result.correct,
          },
        });
      }

      return updated;
    });

    return NextResponse.json(updatedQuiz);
  } catch (error) {
    console.error("Failed to update quiz", error);

    if (error instanceof Prisma.PrismaClientKnownRequestError) {
      if (error.code === "P2002") {
        return NextResponse.json({ error: "Quiz date already exists" }, { status: 409 });
      }
    }

    return NextResponse.json({ error: "Failed to update quiz" }, { status: 500 });
  }
}

export async function DELETE(_: NextRequest, { params }: { params: Promise<{ id: string }> }) {
  const session = await requireAdmin();
  if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });

  const { id } = await params;

  const quiz = await db.dailyQuiz.findUnique({
    where: { id },
    select: {
      id: true,
      isProcessed: true,
    },
  });

  if (!quiz) return NextResponse.json({ error: "Quiz not found" }, { status: 404 });
  if (quiz.isProcessed) {
    return NextResponse.json({ error: "Quiz can no longer be deleted after lottery processing" }, { status: 400 });
  }

  await db.dailyQuiz.delete({ where: { id } });
  return NextResponse.json({ success: true });
}
