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 createOldQuestionPaper = asyncHandler(
//     async (req: Request, res: Response) => {
//         const user = (req as any).user;
//         const { title, exam, year, duration,
//             language,
//             marks,
//             difficulty,
//             publish } = req.body;

//         if (!title) {
//             res.status(400).json({ success: false, message: "title is required" });
//             return;
//         }
//         if (!exam) {
//             res.status(400).json({ success: false, message: "exam is required" });
//             return;
//         }
//         if (!year) {
//             res.status(400).json({ success: false, message: "year is required" });
//             return;
//         }
//         if (!duration) {
//             res.status(400).json({ success: false, message: "duration is required" });
//             return;
//         }
//         if (!marks) {
//             res.status(400).json({ success: false, message: "marks is required" });
//             return;
//         }

//         const exams = await prisma.exam.findUnique({
//             where: {
//                 id: exam as string,
//                 institutionId: user.institutionId,
//             },
//         });

//         if (!exams) {
//             res.status(404).json({
//                 success: false,
//                 message: "exam not found",
//             });
//             return;
//         }


//         const newQuestions = await prisma.oldQuestion.findMany({
//             where: {
//                 institutionId: user.institutionId,
//                 year,
//                 exams: { some: { id: exam as string } },
//             },
//         });

//         const oldQuestionPaper = await prisma.oldQuestionPaper.create({
//             data: {
//                 title,
//                 examId: exam,
//                 language: language || "English",
//                 duration,
//                 marks: parseFloat(marks),
//                 difficulty: difficulty || "Medium",
//                 publish: publish === true || publish === "true",
//                 questions: {
//                     connect: newQuestions.map((val) => ({ id: val.id }))
//                 },
//                 year: year.toString(),
//                 createdById: user.id,
//                 institutionId: user.institutionId,
//             },
//         });

//         res.status(201).json({
//             success: true,
//             message: "Old Question Paper created successfully",
//             data: oldQuestionPaper,
//         });
//     }
// );

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

        const {
            title,
            exam,
            year,
            duration,
            language,
            marks,
            publish,
        } = req.body;

        if (!title) {
            res.status(400).json({ success: false, message: "title is required" });
            return;
        }
        if (!exam) {
            res.status(400).json({ success: false, message: "exam is required" });
            return;
        }
        if (!year) {
            res.status(400).json({ success: false, message: "year is required" });
            return;
        }
        if (!duration) {
            res.status(400).json({ success: false, message: "duration is required" });
            return;
        }
        if (!marks) {
            res.status(400).json({ success: false, message: "marks is required" });
            return;
        }

        const yearStr = String(year);
        const examData = await prisma.exam.findFirst({
            where: {
                id: exam,
                institutionId: user.institutionId,
            },
        });

        if (!examData) {
            res.status(404).json({
                success: false,
                message: "Exam not found",
            });
            return;
        }

        const existOldQuestionPaper = await prisma.oldQuestionPaper.findFirst({ where: { title: { equals: title }, examId: exam, year: { equals: String(year) }, institutionId: user.institutionId } });
        if (existOldQuestionPaper) {
            res.status(400).json({ success: false, message: "Old Question Paper title with year already exist" });
            return;
        }

        // const questions = await prisma.oldQuestion.findMany({
        //     where: {
        //         institutionId: user.institutionId,
        //         year: yearStr,
        //         exams: {
        //             some: { id: exam },
        //         },
        //     },
        //     select: { id: true },
        // });

        const oldQuestionPaper = await prisma.oldQuestionPaper.create({
            data: {
                title,
                examId: exam,
                year: yearStr,
                language: language || "English",
                duration,
                marks: Number(marks),
                publish: publish === true || publish === "true",
                createdById: user.id,
                institutionId: user.institutionId,
                // questions: {
                //     connect: questions.map((q) => ({ id: q.id })),
                // },
            },
        });

        res.status(201).json({
            success: true,
            message: "Old Question Paper created successfully",
            data: {
                id: oldQuestionPaper.id,
                title: oldQuestionPaper.title,
                year: oldQuestionPaper.year,
                totalQuestions: 0,
                publish: oldQuestionPaper.publish,
                createdAt: toIST(oldQuestionPaper.createdAt),
                updatedAt: toIST(oldQuestionPaper.updatedAt),
            },
        });
    }
);

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

        if (!exam) {
            res.status(400).json({ message: "exam is required" });
            return;
        }

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

        const exams = await prisma.exam.findFirst({
            where: {
                id: exam as string,
                institutionId: user.institutionId,
            },
        });

        if (!exams) {
            res.status(404).json({ message: "exam not found" });
            return;
        }

        const whereCondition: any = {
            examId: exam as string,
            institutionId: user.institutionId,
        };

        if (search) {
            whereCondition.OR = [
                {
                    title: {
                        contains: String(search),
                    },
                },
                {
                    year: {
                        contains: String(search),
                    },
                },
            ];
        }

        // total count for pagination
        const totalCount = await prisma.oldQuestionPaper.count({
            where: whereCondition,
        });

        const oldQuestionPapers = await prisma.oldQuestionPaper.findMany({
            where: whereCondition,
            include: {
                _count: {
                    select: {
                        questions: true,
                    },
                },
                referenceSource: {
                    include: {
                        _count: { select: { questions: true } }
                    }
                },
                referenceInstitution: {
                    select: {
                        user: {
                            select: {
                                institutionName: true,
                            }
                        }
                    }
                }
            },
            orderBy: [
                { year: "desc" },
                { title: "asc" },
            ],
            skip,
            take: limitNum,
        });

        res.status(200).json({
            success: true,
            data: oldQuestionPapers.map((p) => ({
                id: p.id,
                title: p.title,
                year: p.year,
                duration: p.duration,
                marks: p.marks,
                language: p.language,
                publish: p.publish,
                referenceSourceId: p.referenceSourceId,
                referenceInstitutionId: p.referenceInstitutionId,
                referenceInstitutionName: p.referenceInstitution?.user?.institutionName,
                totalQuestions: (p as any).referenceSource?._count?.questions ?? p._count.questions,
            })),
            meta: {
                page: pageNum,
                limit: limitNum,
                total: totalCount,
                totalPages: Math.ceil(totalCount / limitNum),
            }
        });
    }
);

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

        const data: any = { ...req.body };

        if (data.year) data.year = data.year.toString();
        if (data.marks) data.marks = parseFloat(data.marks);
        if (data.publish !== undefined) data.publish = data.publish === "true" || data.publish === true;

        // const questions = await prisma.oldQuestion.findMany({
        //     where: {
        //         institutionId: user.institutionId,
        //         year: data.year,
        //         exams: { some: { id: data.exam } },

        //     },
        //     select: { id: true }
        // });

        const existingPaper = await prisma.oldQuestionPaper.findUnique({
            where: { id: id },
        });

        if (!existingPaper) {
            res.status(404).json({ success: false, message: "Old Question Paper not found" });
            return;
        }

        if (existingPaper.referenceSourceId) {
            if (data.publish === undefined) {
                res.status(403).json({ success: false, message: "Cannot edit a shared resource" });
                return;
            }

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

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

        const updateData: any = {
            title: data.title,
            year: data.year,
            marks: data.marks,
            publish: data.publish,
            duration: data.duration,
            language: data.language,
            difficulty: data.difficulty,
        };

        if (data.exam) {
            updateData.exam = { connect: { id: data.exam } };
        }

        // if (questions.length > 0) {
        //     updateData.questions = {
        //         set: questions.map(q => ({ id: q.id }))
        //     };
        // } else if (data.questions && data.questions.set) {
        //     updateData.questions = data.questions;
        // }

        const updatedTest = await prisma.oldQuestionPaper.update({
            where: { id, institutionId: user.institutionId },
            data: updateData
        });
        res.status(200).json({
            message: "Old Question Paper updated successfully",
            data: {
                ...updatedTest,
                createdAt: toIST(updatedTest.createdAt),
                updatedAt: toIST(updatedTest.updatedAt),
            },
        });
    }
);

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

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

    const where: any = {
        examName: { contains: search as string },
        institutionId: user.institutionId,
    };

    const [exams, totalExams, totalQuestions, totalPapers] = await Promise.all([
        prisma.exam.findMany({
            where,
            include: {
                _count: {
                    select: {
                        oldQuestions: true,
                        oldQuestionPapers: true
                    },
                },
            },
            orderBy: { createdAt: "desc" },
            skip,
            take: limitNum,
        }),
        prisma.exam.count({ where }),
        prisma.oldQuestion.count({
            where: {
                institutionId: user.institutionId,
            },
        }),
        prisma.oldQuestionPaper.count({
            where: {
                institutionId: user.institutionId,
                referenceSourceId: null,
            },
        }),
    ]);

    const data = exams.map((e) => {
        return {
            id: e.id,
            examName: e.examName,
            baseExamName: e.examName,
            sharedFromName: null,
            questionsCount: e._count.oldQuestions,
            papersCount: e._count.oldQuestionPapers,
        };
    });

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

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

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

        const paper = await prisma.oldQuestionPaper.findFirst({
            where: {
                id: id as string,
                institutionId: user.institutionId,
            },
            include: {
                questions: { select: { id: true } },
                exam: true,
            },
        });

        if (!paper) {
            res.status(404).json({ message: "Old Question Paper not found", });
            return;
        }

        let questionIds = paper.questions.map((q) => q.id);

        if (paper.referenceSourceId) {
            const sourcePaper = await prisma.oldQuestionPaper.findUnique({
                where: { id: paper.referenceSourceId },
                include: { questions: { select: { id: true } } }
            });
            if (sourcePaper) {
                questionIds = sourcePaper.questions.map((q) => q.id);
            }
        }

        const where: any = {
            // institutionId: user.institutionId,
            id: { in: questionIds },
        };

        if (search) {
            where.OR = [
                { questionText: { contains: search as string } },
                { year: { contains: search as string } },
                { language: { contains: search as string } },
                { explanation: { contains: search as string } },
                {
                    exams: {
                        some: {
                            examName: { contains: search as string },
                        },
                    },
                },
            ];
        }

        const [total, questions] = await Promise.all([
            prisma.oldQuestion.count({ where }),
            prisma.oldQuestion.findMany({
                where,
                include: {
                    exams: { select: { id: true, examName: true } },
                    createdBy: { select: { firstName: true, lastName: true } },
                },
                orderBy: { createdAt: "desc" },
                skip,
                take: limitNum,
            }),
        ]);

        const formattedQuestions = questions.map((question) => ({
            id: question.id,
            questionText: question.questionText,
            year: question.year,
            language: question.language,
            marks: question.marks,
            difficulty: question.difficulty,
            explanation: question.explanation,
            correctAnswer: question.correctAnswer,
            exams: question.exams,
            questionImage: question.questionImage
                ? `${getHost()}${question.questionImage}`
                : "",
            explanationImage: question.explanationImage
                ? `${getHost()}${question.explanationImage}`
                : "",
            options: (question.options as any[]).map((option) => ({
                ...option,
                optionImage: option.optionImage
                    ? `${getHost()}${option.optionImage}`
                    : "",
            })),
            createdBy: question.createdBy
                ? `${question.createdBy.firstName} ${question.createdBy.lastName}`
                : "Unknown",
            createdAt: toIST(question.createdAt),
            updatedAt: toIST(question.updatedAt),
            isShared: !!paper.referenceSourceId
        }));

        res.status(200).json({
            success: true,
            data: {
                id: paper.id,
                examId: paper.examId,
                examName: paper.exam.examName,
                title: paper.title,
                year: paper.year,
                language: paper.language,
                duration: paper.duration,
                marks: paper.marks,
                difficulty: paper.difficulty,
                publish: paper.publish,
                createdAt: toIST(paper.createdAt),
                updatedAt: toIST(paper.updatedAt),
            },
            questions: formattedQuestions,
            meta: {
                total,
                page: pageNum,
                limit: limitNum,
                totalPages: Math.ceil(total / limitNum),
            },
        });
    }
);

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

    const paper = await prisma.oldQuestionPaper.findUnique({
        where: { id, institutionId: user.institutionId }
    });

    if (!paper) {
        res.status(404).json({ message: "Old Question Paper not found" });
        return;
    }

    if (paper.referenceSourceId) {
        res.status(403).json({ success: false, message: "Cannot delete a shared resource." });
        return;
    }

    await prisma.$transaction(async (tx) => {
        await tx.oldQuestionPaper.delete({
            where: { id }
        });

        if (paper.examId) {
            const examUsage = await tx.exam.count({
                where: {
                    id: paper.examId,
                    OR: [
                        { students: { some: {} } },
                        { oldQuestions: { some: {} } },
                        { practiceTests: { some: {} } },
                        { oldQuestionPapers: { some: {} } },
                        { mockTests: { some: {} } },
                        { syllabuses: { some: {} } },
                        { subjectsNotesToExam: { some: {} } },
                    ]
                }
            });
            if (examUsage === 0) {
                await tx.exam.delete({ where: { id: paper.examId } });
            }
        }
    });

    res.status(200).json({ success: true, message: "Old Question Paper deleted successfully" });
});

// Student Old Question Paper List
export const studentOldQuestionPaperList = asyncHandler(async (req: Request, res: Response) => {
    const user = (req as any).user;
    const userId = user.id;
    const studentInstitutionId = user.studentInstitutionId
    const institutionId = user.institutionId

    const { search, attempted, exam, year, language, 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: {
            examResults: {
                select: {
                    oldQuestionPaperId: true
                }
            },
            subscriptions: { where: { isCurrent: true } },
            exam: true,
            student: { select: { language: true } }
        }
    });

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

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

    const attemptedTestIds = new Set(studentInstitution.examResults.map(r => r.oldQuestionPaperId).filter(Boolean));

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

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

    if (year) {
        where.year = { equals: year 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 filterLanguage = (language as string) || mediumOfExam;

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

    //     if (motherTongue) {
    //         languageOr.push({ language: motherTongue });
    //         languageOr.push({ referenceSource: { language: motherTongue } });
    //     }

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

    //     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.oldQuestionPaper.count({ where: baseWhere }),
        prisma.oldQuestionPaper.count({
            where: { ...baseWhere, id: { in: Array.from(attemptedTestIds) as string[] } }
        }),
        prisma.oldQuestionPaper.findMany({
            where,
            include: {
                exam: { select: { examName: true } },
                _count: { select: { questions: true } },
                referenceSource: { include: { _count: { select: { questions: true } } } },
            },
            orderBy: { title: 'asc' },
            skip,
            take: limitNum,
        }),
    ]);

    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 old question papers" : "We will update this year's question paper shortly. Please check another year.",
        data: tests.map(test => ({
            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,
            year: (test as any).referenceSource?.year || test.year,
            marks: (test as any).referenceSource?.marks || test.marks,
            totalQuestions: (test as any).referenceSource?._count?.questions ?? test._count.questions,
            attempted: attemptedTestIds.has(test.id),
        })),
        meta: {
            total,
            page: pageNum,
            limit: limitNum,
            totalPages: Math.ceil(total / limitNum),
            counts: {
                all: allCount,
                attempted: attemptedCount,
                yetToAttempt: yetToAttemptCount
            }
        },
    });
});

// Old Question Paper by ID for students
export const getOldQuestionPaperById = asyncHandler(async (req: Request, res: Response) => {
    const user = (req as any).user;
    const studentInstitutionId = user.studentInstitutionId

    const examId = 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 student subscription has expired
    // if (studentInstitution.subscriptions[0] && studentInstitution.subscriptions[0].status === "EXPIRED") {
    //     res.status(403).json({ message: "Currently you don't have active plan" });
    //     return;
    // }

    // Fetch the record that belongs to this institution (could be a shared copy)
    const institutionPaper = await prisma.oldQuestionPaper.findUnique({
        where: { id: examId, institutionId: user.institutionId },
    });

    if (!institutionPaper) {
        res.status(404).json({ message: "Old Question Paper not found" });
        return;
    }

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

    const sourcePaper = await prisma.oldQuestionPaper.findUnique({
        where: { id: sourcePaperId },
        include: {
            questions: {
                select: {
                    id: true,
                    questionText: true,
                    questionImage: true,
                    options: true,
                },
                orderBy: {
                    createdAt: "asc"
                }
            }
        }
    });

    if (!sourcePaper) {
        res.status(404).json({ message: "Old Question Paper not found" });
        return;
    }

    const totalQuestions = sourcePaper.questions.length;
    const paginatedQuestions = sourcePaper.questions.slice(skip, skip + limitNum);

    const formattedExam = {
        examId: institutionPaper.id, // Use the institution's own record ID so results are stored correctly
        title: sourcePaper.title,
        duration: sourcePaper.duration,
        marks: sourcePaper.marks,
        year: sourcePaper.year,
        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}` : "",
            })),
        })),
    };

    res.status(200).json({
        message: "Old Question Paper fetched successfully",
        data: formattedExam,
        meta: {
            total: totalQuestions,
            page: pageNum,
            limit: limitNum,
            totalPages: Math.ceil(totalQuestions / limitNum)
        }
    });
});