import asyncHandler from "express-async-handler";
import type { Request, Response } from "express";
import { prisma } from "../config/db.ts";
import { getHost } from "../utils/utils.ts";
import { toIST } from "../utils/time.ts";

export const createMockTest = asyncHandler(async (req: Request, res: Response) => {
    const user = (req as any).user;
    const { title, examId, language, duration, totalMarks, questionCount, publish, generationMode, questions } = req.body;

    if (!title || !examId) {
        res.status(400).json({ message: "Title and Exam are required" });
        return;
    }

    if (questions && questions.length > 200) {
        res.status(400).json({ message: "A mock test cannot exceed 200 questions" });
        return;
    }

    const mockTest = await prisma.mockTest.create({
        data: {
            title,
            examId,
            language: language || "English",
            duration: duration ? Number(duration) : 30,
            totalMarks: totalMarks ? Number(totalMarks) : 0,
            questionCount: questionCount ? Number(questionCount) : (questions?.length || 0),
            generationMode: generationMode || "manual",
            publish: publish || false,
            createdById: user.id,
            institutionId: user.institutionId,
            questions: {
                create: questions?.map((q: any) => ({
                    questionId: q.questionId,
                    subjectId: q.subjectId || null,
                    topic: q.topic || null,
                    sourceType: q.sourceType || generationMode || "manual",
                })) || []
            }
        },
        include: { questions: true }
    });

    res.status(201).json({
        message: "Mock Test created successfully",
        data: { ...mockTest, createdAt: toIST(mockTest.createdAt), updatedAt: toIST(mockTest.updatedAt) }
    });
});

export const generateRandomQuestions = asyncHandler(async (req: Request, res: Response) => {
    const user = (req as any).user;
    const { subjectIds, topics, difficulty, language, count, examId, currentMockTestId } = req.body;

    const countNum = Number(count);
    if (!countNum || countNum <= 0 || countNum > 200) {
        res.status(400).json({ message: "Count must be a number between 1 and 200" });
        return;
    }

    const where: any = { institutionId: user.institutionId };

    if (subjectIds && Array.isArray(subjectIds) && subjectIds.length > 0) {
        where.subjectId = { in: subjectIds };
    }
    if (topics && Array.isArray(topics) && topics.length > 0) {
        where.topic = { in: topics };
    }
    if (difficulty) where.difficulty = difficulty;
    if (language) where.language = language;

    if (examId) {
        where.mockTestQuestions = {
            none: {
                mockTest: {
                    examId,
                    ...(currentMockTestId ? { id: { not: currentMockTestId } } : {})
                }
            }
        };
    }

    const totalMatching = await prisma.questionBank.count({ where });
    if (totalMatching === 0) {
        res.status(404).json({ message: "No questions found matching the criteria" });
        return;
    }

    const allIds = await prisma.questionBank.findMany({
        where,
        select: { id: true, subjectId: true }
    });

    const groupedBySubject: Record<string, { id: string }[]> = {};
    for (const q of allIds) {
        const key = q.subjectId || 'unknown';
        if (!groupedBySubject[key]) {
            groupedBySubject[key] = [];
        }
        groupedBySubject[key].push(q);
    }

    for (const key in groupedBySubject) {
        groupedBySubject[key].sort(() => 0.5 - Math.random());
    }

    const selectedIds: string[] = [];
    const availableSubjectIds = Object.keys(groupedBySubject);

    let i = 0;
    while (selectedIds.length < countNum && availableSubjectIds.length > 0) {
        const currentIndex = i % availableSubjectIds.length;
        const subId = availableSubjectIds[currentIndex];
        const group = groupedBySubject[subId];

        if (group.length > 0) {
            selectedIds.push(group.pop()!.id);
            i++;
        } else {
            availableSubjectIds.splice(currentIndex, 1);
        }
    }

    const questions = await prisma.questionBank.findMany({
        where: { id: { in: selectedIds } },
        include: {
            subject: { select: { subjectName: true } }
        }
    });

    res.status(200).json({
        message: "Questions generated successfully",
        totalAvailable: totalMatching,
        data: questions.map(q => ({
            id: q.id,
            questionText: q.questionText,
            questionImage: q.questionImage ? `${getHost()}${q.questionImage}` : "",
            options: (q.options as any || []).map((opt: any) => ({
                option: String(opt?.option) ?? "",
                optionImage: opt.optionImage ? `${getHost()}${opt.optionImage}` : "",
            })),
            marks: q.marks,
            difficulty: q.difficulty,
            subject: q.subject?.subjectName || "",
            subjectId: q.subjectId,
            topic: q.topic || "",
            language: q.language,
            correctAnswer: q.correctAnswer,
            explanation: q.explanation,
            explanationImage: q.explanationImage ? `${getHost()}${q.explanationImage}` : "",
            sourceType: "auto"
        }))
    });
});

export const replaceQuestion = asyncHandler(async (req: Request, res: Response) => {
    const user = (req as any).user;
    const { subjectIds, topics, difficulty, language, examId, currentMockTestId, existingQuestionIds = [] } = req.body;

    const where: any = { institutionId: user.institutionId };

    if (subjectIds && Array.isArray(subjectIds) && subjectIds.length > 0) {
        where.subjectId = { in: subjectIds };
    }
    if (topics && Array.isArray(topics) && topics.length > 0) {
        where.topic = { in: topics };
    }
    if (difficulty) where.difficulty = difficulty;
    if (language) where.language = language;

    const excludeIds = Array.isArray(existingQuestionIds) ? existingQuestionIds : [];
    where.id = { notIn: excludeIds };

    if (examId) {
        where.mockTestQuestions = {
            none: {
                mockTest: {
                    examId,
                    ...(currentMockTestId ? { id: { not: currentMockTestId } } : {})
                }
            }
        };
    }

    const alternativeIds = await prisma.questionBank.findMany({
        where,
        select: { id: true }
    });

    if (alternativeIds.length === 0) {
        res.status(404).json({ message: "No alternative questions found matching your criteria" });
        return;
    }

    const randomPick = alternativeIds[Math.floor(Math.random() * alternativeIds.length)];

    const question = await prisma.questionBank.findUnique({
        where: { id: randomPick.id },
        include: {
            subject: { select: { subjectName: true } }
        }
    });

    if (!question) {
        res.status(404).json({ message: "Question retrieval failed" });
        return;
    }

    res.status(200).json({
        message: "Alternative question found successfully",
        data: {
            id: question.id,
            questionText: question.questionText,
            questionImage: question.questionImage ? `${getHost()}${question.questionImage}` : "",
            options: (question.options as any || []).map((opt: any) => ({
                option: String(opt?.option) ?? "",
                optionImage: opt.optionImage ? `${getHost()}${opt.optionImage}` : "",
            })),
            marks: question.marks,
            difficulty: question.difficulty,
            subject: question.subject?.subjectName || "",
            subjectId: question.subjectId,
            topic: question.topic || "",
            language: question.language,
            correctAnswer: question.correctAnswer,
            explanation: question.explanation,
            explanationImage: question.explanationImage ? `${getHost()}${question.explanationImage}` : "",
            sourceType: "auto"
        }
    });
});

export const listMockTests = asyncHandler(async (req: Request, res: Response) => {
    const user = (req as any).user;
    const { search, examId, page = "1", limit = "10" } = req.query;

    const pageNum = Number(page);
    const limitNum = Number(limit);
    const skip = (pageNum - 1) * limitNum;

    const where: any = { institutionId: user.institutionId };

    if (examId) where.examId = examId;
    if (search) where.title = { contains: search as string };

    const [tests, totalCount] = await prisma.$transaction([
        prisma.mockTest.findMany({
            where,
            include: {
                exam: { select: { examName: true } },
                _count: { select: { questions: true } },
                referenceInstitution: {
                    select: {
                        user: { select: { institutionName: true } }
                    }
                }
            },
            orderBy: { createdAt: "desc" },
            skip, take: limitNum
        }),
        prisma.mockTest.count({ where })
    ]);

    const resolvedTests = await Promise.all(tests.map(async (test) => {
        let questionCount = test._count.questions;
        if (test.referenceSourceId) {
            questionCount = await prisma.mockTestQuestion.count({
                where: { mockTestId: test.referenceSourceId, isActive: true }
            });
        }
        return {
            ...test,
            questionCount,
            _count: {
                ...test._count,
                questions: questionCount
            },
            createdAt: toIST(test.createdAt),
            updatedAt: toIST(test.updatedAt)
        };
    }));

    res.status(200).json({
        data: resolvedTests,
        meta: {
            total: totalCount,
            page: pageNum,
            limit: limitNum,
            totalPages: Math.ceil(totalCount / limitNum),
        }
    });
});

export const updateMockTest = asyncHandler(async (req: Request, res: Response) => {
    const user = (req as any).user;
    const { id } = req.params;
    const { title, language, duration, totalMarks, questionCount, publish, generationMode, questions } = req.body;

    const existing = await prisma.mockTest.findFirst({
        where: { id, institutionId: user.institutionId }
    });

    if (!existing) {
        res.status(404).json({ message: "Mock Test not found" });
        return;
    }

    if (existing.referenceSourceId) {
        if (publish === undefined) {
            res.status(403).json({ message: "You cannot edit a mock test shared by another institution." });
            return;
        }

        const updatedTest = await prisma.mockTest.update({
            where: { id, institutionId: user.institutionId },
            data: { publish }
        });

        res.status(200).json({
            message: "Mock Test publish status updated successfully",
            data: { ...updatedTest, createdAt: toIST(updatedTest.createdAt), updatedAt: toIST(updatedTest.updatedAt) }
        });
        return;
    }

    const updateData: any = {
        title: title || existing.title,
        language: language ?? existing.language,
        duration: duration !== undefined ? Number(duration) : existing.duration,
        totalMarks: totalMarks !== undefined ? Number(totalMarks) : existing.totalMarks,
        generationMode: generationMode || existing.generationMode,
        publish: publish !== undefined ? publish : existing.publish,
    };

    if (questions !== undefined) {
        await prisma.mockTestQuestion.deleteMany({ where: { mockTestId: id } });
        updateData.questionCount = questionCount !== undefined ? Number(questionCount) : (questions?.length || 0);
        updateData.questions = {
            create: questions?.map((q: any) => ({
                questionId: q.questionId,
                subjectId: q.subjectId || null,
                topic: q.topic || null,
                sourceType: q.sourceType || "manual",
            })) || []
        };
    } else if (questionCount !== undefined) {
        updateData.questionCount = Number(questionCount);
    }

    const mockTest = await prisma.mockTest.update({
        where: { id },
        data: updateData,
        include: { questions: true }
    });

    res.status(200).json({
        message: "Mock Test updated successfully",
        data: { ...mockTest, createdAt: toIST(mockTest.createdAt), updatedAt: toIST(mockTest.updatedAt) }
    });
});

export const getMockTestById = asyncHandler(async (req: Request, res: Response) => {
    const user = (req as any).user;
    const { id } = req.params;

    const institutionMockTest = await prisma.mockTest.findFirst({
        where: { id, institutionId: user.institutionId },
    });

    if (!institutionMockTest) {
        res.status(404).json({ message: "Mock Test not found" });
        return;
    }

    const sourceTestId = institutionMockTest.referenceSourceId || institutionMockTest.id;

    const sourceMockTest = await prisma.mockTest.findFirst({
        where: { id: sourceTestId },
        include: {
            questions: {
                include: {
                    question: {
                        include: { subject: { select: { subjectName: true } } }
                    },
                    subject: { select: { subjectName: true } }
                },
                orderBy: { createdAt: 'asc' }
            }
        }
    });

    if (!sourceMockTest) {
        res.status(404).json({ message: "Mock Test not found" });
        return;
    }

    res.status(200).json({
        data: {
            ...institutionMockTest,
            title: sourceMockTest.title,
            duration: sourceMockTest.duration,
            totalMarks: sourceMockTest.totalMarks,
            questionCount: sourceMockTest.questionCount,
            questions: sourceMockTest.questions.map(q => ({
                id: q.questionId,
                questionText: q.question.questionText,
                questionImage: q.question.questionImage ? `${getHost()}${q.question.questionImage}` : "",
                options: (q.question.options as any || []).map((opt: any) => ({
                    option: String(opt?.option) ?? "",
                    optionImage: opt.optionImage ? `${getHost()}${opt.optionImage}` : "",
                })),
                marks: q.question.marks,
                difficulty: q.question.difficulty,
                subject: q.subject?.subjectName || q.question?.subject?.subjectName || "",
                topic: q.topic || q.question?.topic || "",
                language: q.question.language,
                correctAnswer: q.question.correctAnswer,
                explanation: q.question.explanation,
                explanationImage: q.question.explanationImage ? `${getHost()}${q.question.explanationImage}` : "",
                mockTestQuestionId: q.id,
                sourceType: q.sourceType
            })),
            createdAt: toIST(institutionMockTest.createdAt),
            updatedAt: toIST(institutionMockTest.updatedAt)
        }
    });
});

export const getAvailableQuestionCount = asyncHandler(async (req: Request, res: Response) => {
    const user = (req as any).user;
    const { subjectIds, topics, difficulty, language, examId, currentMockTestId } = req.body;

    const whereBase: any = { institutionId: user.institutionId };

    if (subjectIds && Array.isArray(subjectIds) && subjectIds.length > 0) {
        whereBase.subjectId = { in: subjectIds };
    }
    if (topics && Array.isArray(topics) && topics.length > 0) {
        whereBase.topic = { in: topics };
    }
    if (difficulty) whereBase.difficulty = difficulty;
    if (language) whereBase.language = language;

    const whereAvailable: any = { ...whereBase };
    if (examId) {
        whereAvailable.mockTestQuestions = {
            none: {
                mockTest: {
                    examId,
                    ...(currentMockTestId ? { id: { not: currentMockTestId } } : {})
                }
            }
        };
    }

    const whereUsed: any = { ...whereBase };
    if (examId) {
        whereUsed.mockTestQuestions = {
            some: {
                mockTest: {
                    examId,
                    ...(currentMockTestId ? { id: { not: currentMockTestId } } : {})
                }
            }
        };
    }

    const availableCount = await prisma.questionBank.count({ where: whereAvailable });
    const usedCount = await prisma.questionBank.count({ where: whereUsed });
    const totalCount = availableCount + usedCount;

    res.status(200).json({
        message: "Count fetched successfully",
        available: availableCount,
        used: usedCount,
        total: totalCount,
        count: availableCount
    });
});

export const deleteMockTest = asyncHandler(async (req: Request, res: Response) => {
    const user = (req as any).user;
    const { id } = req.params;

    const existing = await prisma.mockTest.findFirst({
        where: { id, institutionId: user.institutionId }
    });

    if (!existing) {
        res.status(404).json({ message: "Mock Test not found" });
        return;
    }

    if (existing.referenceSourceId) {
        res.status(403).json({ message: "You cannot delete a mock test shared by another institution." });
        return;
    }

    await prisma.mockTest.delete({ where: { id } });

    res.status(200).json({ message: "Mock Test deleted successfully" });
});

// Student MockTest List
export const studentMockTestList = asyncHandler(async (req: Request, res: Response) => {
    const user = (req as any).user;
    const studentInstitutionId = user.studentInstitutionId;
    const institutionId = user.institutionId;

    const { search, attempted, exam, language, page = "1", limit = "10" } = req.query;

    const fetchAll = limit === 'all';

    const pageNum = parseInt(page as string);
    const limitNum = parseInt(limit as string);

    const safePageNum = isNaN(pageNum) ? 1 : pageNum;
    const safeLimitNum = isNaN(limitNum) ? 10 : limitNum;
    const skip = (safePageNum - 1) * safeLimitNum;

    const studentInstitution = await prisma.studentInstitution.findUnique({
        where: { id: studentInstitutionId, deletedAt: null },
        include: {
            subscriptions: { where: { isCurrent: true } },
            exam: true,
            student: { include: { user: { select: { details: true } } } }
        }
    });

    if (!studentInstitution || !studentInstitution.institutionId) {
        res.status(404).json({ message: "Student record not found" });
        return;
    }

    // If student subscription has expired
    // if (studentInstitution.subscriptions[0] && studentInstitution.subscriptions[0].status === "EXPIRED") {
    //     res.status(403).json({ message: "Currently you don't have an active plan" });
    //     return;
    // }

    const results = await prisma.mockTestResult.findMany({
        where: { studentInstitutionId },
        select: { mockTestId: true }
    });
    const attemptedTestIds = new Set(results.map(r => r.mockTestId));

    const where: any = {
        publish: true,
        institutionId: institutionId,
    };

    if (search) {
        where.title = { contains: search as string };
    }

    if (exam) {
        where.examId = exam as string;
    } else if (studentInstitution.examsId) {
        where.examId = studentInstitution.examsId;
    }

    const motherTongue = studentInstitution.student?.language || studentInstitution.language || "";
    const mediumOfExam = studentInstitution.student?.language ? (studentInstitution.language || "English") : "English";
    const targetLanguage = language || mediumOfExam;

    if (motherTongue || targetLanguage) {
        const languageOr: any[] = [];

        if (motherTongue) {
            languageOr.push(
                { questions: { some: { subject: { language: motherTongue } } } },
                { referenceSource: { questions: { some: { subject: { language: motherTongue } } } } }
            );
        }

        if (targetLanguage) {
            languageOr.push(
                { language: targetLanguage },
                { referenceSource: { language: targetLanguage } }
            );
        }

        if (languageOr.length > 0) {
            where.AND = [
                ...(where.AND || []),
                { OR: languageOr }
            ];
        }
    }

    const baseWhere = { ...where };

    if (attempted === "true") {
        where.id = { in: Array.from(attemptedTestIds) as string[] };
    } else if (attempted === "false") {
        where.id = { notIn: Array.from(attemptedTestIds) as string[] };
    }

    const [allCount, attemptedCount, tests] = await Promise.all([
        prisma.mockTest.count({ where: baseWhere }),
        prisma.mockTest.count({
            where: { ...baseWhere, id: { in: Array.from(attemptedTestIds) as string[] } }
        }),
        prisma.mockTest.findMany({
            where,
            include: {
                exam: { select: { examName: true } },
                referenceSource: { select: { title: true, duration: true, totalMarks: true, questionCount: true } },
            },
            orderBy: { title: 'asc' },
            ...(!fetchAll && {
                skip,
                take: safeLimitNum,
            }),
        }),
    ]);

    const yetToAttemptCount = allCount - attemptedCount;

    let total = allCount;
    if (attempted === "true") total = attemptedCount;
    else if (attempted === "false") total = yetToAttemptCount;

    res.status(200).json({
        message: tests.length > 0 ? "Successfully fetched Mock tests" : "We will update soon.",
        data: tests.map(test => {
            const marks = (test as any).referenceSource?.totalMarks || test.totalMarks;
            const totalQs = (test as any).referenceSource?.questionCount || test.questionCount;
            return {
                id: test.id,
                exam: test.exam?.examName,
                language: test.language,
                title: (test as any).referenceSource?.title || test.title,
                duration: (test as any).referenceSource?.duration || test.duration,
                marks: marks,
                totalQuestions: totalQs,
                markPerQuestion: marks > 0 && totalQs > 0 ? (marks / totalQs) : 1,
                attempted: attemptedTestIds.has(test.id),
            };
        }),
        meta: {
            total,
            page: fetchAll ? 1 : safePageNum,
            limit: fetchAll ? total : safeLimitNum,
            totalPages: fetchAll ? 1 : Math.ceil(total / safeLimitNum),
            counts: {
                all: allCount,
                attempted: attemptedCount,
                yetToAttempt: yetToAttemptCount
            }
        },
    });
});

// Get Mock Test by ID for student
export const getMockTestByIdForStudent = asyncHandler(async (req: Request, res: Response) => {
    const user = (req as any).user;
    const studentInstitutionId = user.studentInstitutionId;
    const testId = req.params.id;
    const { page = "1", limit = "10" } = req.query;

    const pageNum = parseInt(page as string);
    const limitNum = parseInt(limit as string);
    const skip = (pageNum - 1) * limitNum;

    const studentInstitution = await prisma.studentInstitution.findUnique({
        where: { id: studentInstitutionId },
        include: { subscriptions: { where: { isCurrent: true } } }
    });

    if (!studentInstitution) {
        res.status(404).json({ message: "Student record not found" });
        return;
    }

    // If student subscription has expired
    // if (studentInstitution.subscriptions[0] && studentInstitution.subscriptions[0].status === "EXPIRED") {
    //     res.status(403).json({ message: "Currently you don't have an active plan" });
    //     return;
    // }

    // Fetch the record that belongs to this institution (could be a shared copy)
    const institutionMockTest = await prisma.mockTest.findFirst({
        where: { id: testId, institutionId: user.institutionId },
    });

    if (!institutionMockTest) {
        res.status(404).json({ message: "Mock Test not found" });
        return;
    }

    // If this is a shared copy, resolve questions live from the original source
    const sourceTestId = institutionMockTest.referenceSourceId || institutionMockTest.id;

    const sourceMockTest = await prisma.mockTest.findFirst({
        where: { id: sourceTestId },
        include: {
            questions: {
                where: { isActive: true },
                include: {
                    question: {
                        select: {
                            id: true,
                            questionText: true,
                            questionImage: true,
                            options: true,
                        }
                    }
                },
                orderBy: { createdAt: "asc" }
            }
        }
    });

    if (!sourceMockTest) {
        res.status(404).json({ message: "Mock Test not found" });
        return;
    }

    const mappedQuestions = sourceMockTest.questions.map((mtq: any) => mtq.question);
    const paginatedQuestions = mappedQuestions.slice(skip, skip + limitNum);

    const markPerQuestion = (sourceMockTest.totalMarks > 0 && mappedQuestions.length > 0)
        ? (sourceMockTest.totalMarks / mappedQuestions.length) : 1;

    const formattedTest = {
        testId: institutionMockTest.id, // Use the institution's own record ID so results are stored correctly
        title: sourceMockTest.title,
        duration: sourceMockTest.duration,
        marks: sourceMockTest.totalMarks,
        questions: paginatedQuestions.map((q: any) => ({
            id: q.id,
            questionText: q.questionText,
            questionImage: q.questionImage ? `${getHost()}${q.questionImage}` : "",
            options: (q.options as any[] || []).map((opt: any) => ({
                option: String(opt?.option) || "",
                optionImage: opt.optionImage ? `${getHost()}${opt.optionImage}` : "",
            })),
            marks: markPerQuestion
        })),
        totalQuestions: mappedQuestions.length,
        meta: {
            total: mappedQuestions.length,
            page: pageNum,
            limit: limitNum,
            totalPages: Math.ceil(mappedQuestions.length / limitNum),
        }
    };

    res.status(200).json({
        message: "Mock Test fetched successfully",
        data: formattedTest,
    });
});

export const submitMockTest = asyncHandler(async (req: Request, res: Response) => {
    const user = (req as any).user;
    const userId = user.id;
    const institutionId = user.institutionId;
    const studentInstitutionId = user.studentInstitutionId;

    const { testId, answers } = req.body;

    if (!testId || !answers) {
        res.status(400).json({ message: "testId & answers are required" });
        return;
    }

    const studentProfile = await prisma.student.findUnique({
        where: { userId: userId }
    });

    if (!studentProfile) {
        res.status(404).json({ message: "Student profile matching this account was not found" });
        return;
    }

    const studentId = studentProfile.id;

    const test = await prisma.mockTest.findUnique({
        where: { id: testId, institutionId },
    });

    if (!test) {
        res.status(404).json({ message: "Mock Test not found" });
        return;
    }

    const sourceTestId = test.referenceSourceId || test.id;

    const sourceMockTest = await prisma.mockTest.findFirst({
        where: { id: sourceTestId },
        include: {
            questions: {
                where: { isActive: true },
                include: {
                    question: {
                        select: {
                            id: true,
                            questionText: true,
                            questionImage: true,
                            options: true,
                            correctAnswer: true,
                            marks: true,
                            difficulty: true,
                            explanation: true,
                            explanationImage: true
                        }
                    }
                }
            }
        }
    });

    if (!sourceMockTest) {
        res.status(404).json({ message: "Source Mock Test not found" });
        return;
    }

    let totalMarks = 0;
    let obtainedMarks = 0;
    let correctCount = 0;
    let wrongCount = 0;

    const validationDetails: any[] = [];
    const detailsDataForDb: any[] = [];

    sourceMockTest.questions.forEach((mtq: any) => {
        const q = mtq.question;
        const questionId = q.id;
        const selectedAnswerIndex = answers[questionId];
        const correctIndex = q.correctAnswer;
        
        const markPerQuestion = (sourceMockTest.totalMarks > 0 && sourceMockTest.questionCount > 0)
            ? (sourceMockTest.totalMarks / sourceMockTest.questionCount)
            : (q.marks || 1);
        const mark = markPerQuestion;

        totalMarks += mark;

        const selectedExist = selectedAnswerIndex != null;
        const isCorrect = selectedExist && selectedAnswerIndex == correctIndex;

        if (isCorrect) {
            correctCount++;
            obtainedMarks += mark;
        } else {
            wrongCount++;
        }

        const optionsArray = Array.isArray(q.options) ? q.options : [];

        validationDetails.push({
            questionId,
            questionText: q.questionText,
            questionImage: q.questionImage ? `${getHost()}${q.questionImage}` : "",
            options: optionsArray.map((option: any) => ({
                option: String(option.option) ?? "",
                optionImage: option.optionImage ? `${getHost()}${option.optionImage}` : "",
            })),
            correctAnswerIndex: correctIndex,
            difficulty: q.difficulty,
            selectedAnswerIndex: selectedExist ? selectedAnswerIndex : null,
            isCorrect: selectedExist ? isCorrect : null,
            explanation: q.explanation ?? "",
            explanationImage: q.explanationImage ? `${getHost()}${q.explanationImage}` : "",
            marks: markPerQuestion
        });

        detailsDataForDb.push({
            questionId,
            selectedOption: selectedExist ? selectedAnswerIndex : null,
            isCorrect: selectedExist ? isCorrect : null,
            obtainedMarks: isCorrect ? mark : 0,
        });
    });

    const computedPercentage = totalMarks > 0 ? (obtainedMarks / totalMarks) * 100 : 0;

    const result = await prisma.mockTestResult.create({
        data: {
            mockTestId: testId,
            studentId,
            studentInstitutionId,
            totalMarks,
            obtainedMarks,
            details: {
                create: detailsDataForDb
            }
        }
    });

    const testMarkPerQuestion = (sourceMockTest.totalMarks > 0 && sourceMockTest.questionCount > 0)
        ? (sourceMockTest.totalMarks / sourceMockTest.questionCount)
        : 1;

    res.status(200).json({
        message: "Mock Test submitted successfully",
        result: {
            resultId: result.id,
            totalQuestions: sourceMockTest.questions.length,
            totalMarks,
            obtainedMarks,
            correctCount,
            wrongCount,
            markPerQuestion: testMarkPerQuestion,
            percentage: computedPercentage.toFixed(2),
            validationDetails
        }
    });
});

export const getLastMockTest = asyncHandler(async (req: Request, res: Response) => {
    const user = (req as any).user;
    const userId = user.id;
    const studentInstitutionId = user.studentInstitutionId;

    const responseData: any = {
        testTitle: "",
        createdAt: "",
        obtainedMarks: 0,
        totalMarks: 0,
        correctCount: 0,
        wrongCount: 0,
        percentage: "0.00",
        validationDetails: [],
    };

    const studentProfile = await prisma.student.findUnique({
        where: { userId: userId },
    });

    if (!studentProfile) {
        res.status(404).json({
            message: "Student not found",
        });
        return;
    }

    const studentId = studentProfile.id;

    const studentInstitution = studentInstitutionId
        ? await prisma.studentInstitution.findUnique({
              where: { id: studentInstitutionId },
              select: { examsId: true, language: true, student: { select: { language: true } } },
          })
        : null;

    const motherTongue = studentInstitution?.student?.language || studentInstitution?.language || "";
    const filterLanguage = studentInstitution?.student?.language ? (studentInstitution?.language || "English") : "English";

    const enrolledExamId = studentInstitution?.examsId ?? null;

        const mockTestFilter: any = {};
        if (enrolledExamId) mockTestFilter.examId = enrolledExamId;

        if (motherTongue || filterLanguage) {
            const langOr: any[] = [];

            if (filterLanguage) {
                langOr.push({ language: filterLanguage });
                langOr.push({ referenceSource: { language: filterLanguage } });
            }

            if (motherTongue) {
                langOr.push({ questions: { some: { question: { subject: { language: motherTongue } } } } });
                langOr.push({ referenceSource: { questions: { some: { question: { subject: { language: motherTongue } } } } } });
            }

            if (langOr.length > 0) {
                mockTestFilter.OR = langOr;
            }
        }

        const lastMockResult = await prisma.mockTestResult.findFirst({
            where: {
                studentId: studentId,
                studentInstitutionId: studentInstitutionId,
                mockTest: mockTestFilter,
            },
        include: {
            mockTest: {
                include: {
                    questions: {
                        where: { isActive: true },
                        include: {
                            question: { include: { subject: true } },
                        },
                    },
                },
            },
            details: true,
        },
        orderBy: {
            createdAt: "desc",
        },
    });

    if (!lastMockResult) {
        res.status(404).json({
            message: "No mock test attempts found",
        });
        return;
    }

    responseData.testTitle = lastMockResult.mockTest?.title || "Mock Test";
    responseData.createdAt = lastMockResult.createdAt;

    let testQuestions = lastMockResult.mockTest?.questions || [];

    if (testQuestions.length === 0 && lastMockResult.mockTest?.referenceSourceId) {
        const sourceMockTest = await prisma.mockTest.findUnique({
            where: { id: lastMockResult.mockTest.referenceSourceId },
            include: {
                questions: {
                    where: { isActive: true },
                    include: { question: { include: { subject: true } } }
                }
            }
        });
        if (sourceMockTest) {
            testQuestions = sourceMockTest.questions;
        }
    }

    const testAnswers = lastMockResult.details || [];
    const sourceTestTotalMarks = lastMockResult.mockTest?.totalMarks || 0;
    const sourceTestQuestionCount = lastMockResult.mockTest?.questionCount || 0;
    const markPerQuestion = (sourceTestTotalMarks > 0 && sourceTestQuestionCount > 0)
        ? (sourceTestTotalMarks / sourceTestQuestionCount)
        : 1;

    testQuestions.forEach((mtq: any) => {
        const q = mtq.question;
        if (!q) return;

        const questionId = q.id;

        const studentSubmission = testAnswers.find(
            (t: any) => t.questionId === questionId
        );

        const selectedAnswerIndex = studentSubmission?.selectedOption ?? null;
        const correctIndex = q.correctAnswer;
        const mark = markPerQuestion;

        responseData.totalMarks += mark;

        const selectedExist = selectedAnswerIndex !== null;
        const isCorrect = selectedExist && selectedAnswerIndex == correctIndex;

        if (isCorrect) {
            responseData.correctCount++;
            responseData.obtainedMarks += mark;
        } else {
            responseData.wrongCount++;
        }

        const optionsArray = Array.isArray(q.options) ? q.options : [];

        responseData.validationDetails.push({
            questionId,
            questionText: q.questionText,
            questionImage: q.questionImage ? `${getHost()}${q.questionImage}` : "",
            options: optionsArray.map((option: any) => ({
                option: option?.option || "",
                optionImage: option?.optionImage ? `${getHost()}${option.optionImage}` : "",
            })),
            correctAnswerIndex: correctIndex,
            difficulty: q.difficulty,
            selectedAnswerIndex,
            isCorrect: selectedExist ? isCorrect : null,
            explanation: q.explanation || "",
            explanationImage: q.explanationImage ? `${getHost()}${q.explanationImage}` : "",
            marks: markPerQuestion
        });
    });

    responseData.percentage = responseData.totalMarks > 0
        ? ((responseData.obtainedMarks / responseData.totalMarks) * 100).toFixed(2)
        : "0.00";

    responseData.markPerQuestion = markPerQuestion;

    res.status(200).json({
        message: "Last mock test details fetched successfully",
        result: responseData,
    });
});