import { prisma } from '../config/database';
import { Prisma } from '@prisma/client';
import { config } from '../config';
import { logger } from '../config/logger';
import { UnauthorizedError, ValidationError, ForbiddenError, NotFoundError } from '../middleware/errorHandler';
import jwt from 'jsonwebtoken';
import { uploadFile, deleteFile, getPresignedUrl } from '../config/minio';
import {
    CreateCourseInput,
    UpdateCourseInput,
    createCourseResponse,
    GetMyCourseResponse,
    ListMyCourseResponse,
    addinstructorCourse,
    addinstructorCourseResponse,
    removeinstructorCourse,
    removeinstructorCourseResponse,
    setprimaryCourseInstructor,
    setprimaryCourseInstructorResponse,
    submitCourseResponse,
    listinstructorCourseResponse,
    sendCourseForReview,
    getmyCourse,
    listinstructorCourse,
    SearchInstructorInput,
    SearchInstructorResponse,
    GetEnrolledStudentsInput,
    GetEnrolledStudentsResponse,
    GetQuizScoresInput,
    GetQuizScoresResponse,
    GetQuizAttemptDetailInput,
    GetQuizAttemptDetailResponse,
    GetEnrolledStudentDetailInput,
    GetEnrolledStudentDetailResponse,
} from "../types/CoursesInstructor.types";

export class CoursesInstructorService {
    static async createCourse(courseData: CreateCourseInput, userId: number, thumbnailFile?: Express.Multer.File): Promise<createCourseResponse> {
        try {
            let thumbnailUrl: string | undefined;

            // Upload thumbnail to MinIO if provided
            if (thumbnailFile) {
                const timestamp = Date.now();
                const uniqueId = Math.random().toString(36).substring(2, 15);
                const extension = thumbnailFile.originalname.split('.').pop() || 'jpg';
                const safeFilename = `${timestamp}-${uniqueId}.${extension}`;
                const filePath = `courses/thumbnails/${safeFilename}`;

                await uploadFile(filePath, thumbnailFile.buffer, thumbnailFile.mimetype || 'image/jpeg');
                thumbnailUrl = filePath;
            }

            // Use transaction to create course and instructor together
            const result = await prisma.$transaction(async (tx) => {
                // Create the course
                const courseCreated = await tx.course.create({
                    data: {
                        category_id: courseData.category_id,
                        title: courseData.title,
                        slug: courseData.slug,
                        description: courseData.description,
                        thumbnail_url: thumbnailUrl,
                        price: courseData.price || 0,
                        is_free: courseData.is_free ?? false,
                        have_certificate: courseData.have_certificate ?? false,
                        created_by: userId,
                        status: 'DRAFT'
                    }
                });

                // Add creator as primary instructor
                await tx.courseInstructor.create({
                    data: {
                        course_id: courseCreated.id,
                        user_id: userId,
                        is_primary: true,
                    }
                });

                return courseCreated;
            });

            return {
                code: 201,
                message: 'Course created successfully',
                data: result
            };
        } catch (error) {
            logger.error('Failed to create course', { error });
            throw error;
        }
    }

    static async listMyCourses(token: string): Promise<ListMyCourseResponse> {
        try {
            const decoded = jwt.verify(token, config.jwt.secret) as { id: number; type: string };
            const courseInstructors = await prisma.courseInstructor.findMany({
                where: {
                    user_id: decoded.id
                },
                include: {
                    course: true
                }
            });

            const courses = await Promise.all(
                courseInstructors.map(async (ci) => {
                    let thumbnail_presigned_url: string | null = null;
                    if (ci.course.thumbnail_url) {
                        try {
                            thumbnail_presigned_url = await getPresignedUrl(ci.course.thumbnail_url, 3600);
                        } catch (err) {
                            logger.warn(`Failed to generate presigned URL for thumbnail: ${err}`);
                        }
                    }
                    return {
                        ...ci.course,
                        thumbnail_url: thumbnail_presigned_url,
                    };
                })
            );

            return {
                code: 200,
                message: 'Courses retrieved successfully',
                data: courses,
                total: courses.length
            };
        } catch (error) {
            logger.error('Failed to retrieve courses', { error });
            throw error;
        }
    }

    static async getmyCourse(getmyCourse: getmyCourse): Promise<GetMyCourseResponse> {
        try {
            const decoded = jwt.verify(getmyCourse.token, config.jwt.secret) as { id: number; type: string };

            // Check if user is instructor of this course
            const courseInstructor = await prisma.courseInstructor.findFirst({
                where: {
                    user_id: decoded.id,
                    course_id: getmyCourse.course_id
                },
                include: {
                    course: {
                        include: {
                            chapters: {
                                include: {
                                    lessons: {
                                        include: {
                                            attachments: true,
                                            progress: true,
                                            quiz: true
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            });

            if (!courseInstructor) {
                throw new ForbiddenError('You are not an instructor of this course');
            }

            // Generate presigned URL for thumbnail
            let thumbnail_presigned_url: string | null = null;
            if (courseInstructor.course.thumbnail_url) {
                try {
                    thumbnail_presigned_url = await getPresignedUrl(courseInstructor.course.thumbnail_url, 3600);
                } catch (err) {
                    logger.warn(`Failed to generate presigned URL for thumbnail: ${err}`);
                }
            }

            return {
                code: 200,
                message: 'Course retrieved successfully',
                data: {
                    ...courseInstructor.course,
                    thumbnail_url: thumbnail_presigned_url,
                }
            };
        } catch (error) {
            logger.error('Failed to retrieve course', { error });
            throw error;
        }
    }

    static async updateCourse(token: string, courseId: number, courseData: UpdateCourseInput): Promise<createCourseResponse> {
        try {
            await this.validateCourseInstructor(token, courseId);

            const course = await prisma.course.update({
                where: {
                    id: courseId
                },
                data: courseData
            });

            return {
                code: 200,
                message: 'Course updated successfully',
                data: course
            };
        } catch (error) {
            logger.error('Failed to update course', { error });
            throw error;
        }
    }

    static async uploadThumbnail(token: string, courseId: number, file: Express.Multer.File): Promise<{ code: number; message: string; data: { course_id: number; thumbnail_url: string } }> {
        try {
            await this.validateCourseInstructor(token, courseId);

            // Get current course to check for existing thumbnail
            const currentCourse = await prisma.course.findUnique({
                where: { id: courseId }
            });

            // Delete old thumbnail if exists
            if (currentCourse?.thumbnail_url) {
                try {
                    await deleteFile(currentCourse.thumbnail_url);
                    logger.info(`Deleted old thumbnail: ${currentCourse.thumbnail_url}`);
                } catch (error) {
                    logger.warn(`Failed to delete old thumbnail: ${error}`);
                }
            }

            // Generate unique filename
            const timestamp = Date.now();
            const uniqueId = Math.random().toString(36).substring(2, 15);
            const extension = file.originalname.split('.').pop() || 'jpg';
            const safeFilename = `${timestamp}-${uniqueId}.${extension}`;
            const filePath = `courses/${courseId}/thumbnail/${safeFilename}`;

            // Upload to MinIO
            await uploadFile(filePath, file.buffer, file.mimetype || 'image/jpeg');
            logger.info(`Uploaded thumbnail: ${filePath}`);

            // Update course with new thumbnail path
            await prisma.course.update({
                where: { id: courseId },
                data: { thumbnail_url: filePath }
            });

            // Generate presigned URL for response
            const presignedUrl = await getPresignedUrl(filePath, 3600);

            return {
                code: 200,
                message: 'Thumbnail uploaded successfully',
                data: {
                    course_id: courseId,
                    thumbnail_url: presignedUrl
                }
            };
        } catch (error) {
            logger.error('Failed to upload thumbnail', { error });
            throw error;
        }
    }

    static async deleteCourse(token: string, courseId: number): Promise<createCourseResponse> {
        try {
            const courseInstructorId = await this.validateCourseInstructor(token, courseId);
            if (!courseInstructorId.is_primary) {
                throw new ForbiddenError('You have no permission to delete this course');
            }

            const course = await prisma.course.delete({
                where: {
                    id: courseId
                }
            });
            return {
                code: 200,
                message: 'Course deleted successfully',
                data: course
            };
        } catch (error) {
            logger.error('Failed to delete course', { error });
            throw error;
        }
    }

    static async sendCourseForReview(sendCourseForReview: sendCourseForReview): Promise<submitCourseResponse> {
        try {
            const decoded = jwt.verify(sendCourseForReview.token, config.jwt.secret) as { id: number; type: string };
            await prisma.courseApproval.create({
                data: {
                    course_id: sendCourseForReview.course_id,
                    submitted_by: decoded.id,
                }
            });
            await prisma.course.update({
                where: {
                    id: sendCourseForReview.course_id
                },
                data: {
                    status: 'PENDING'
                }
            });
            return {
                code: 200,
                message: 'Course sent for review successfully',
            };
        } catch (error) {
            logger.error('Failed to send course for review', { error });
            throw error;
        }
    }

    static async getCourseApprovals(token: string, courseId: number): Promise<{
        code: number;
        message: string;
        data: any[];
        total: number;
    }> {
        try {
            const decoded = jwt.verify(token, config.jwt.secret) as { id: number; type: string };

            // Validate instructor access
            await this.validateCourseInstructor(token, courseId);

            const approvals = await prisma.courseApproval.findMany({
                where: { course_id: courseId },
                orderBy: { created_at: 'desc' },
                include: {
                    submitter: {
                        select: { id: true, username: true, email: true }
                    },
                    reviewer: {
                        select: { id: true, username: true, email: true }
                    }
                }
            });

            return {
                code: 200,
                message: 'Course approvals retrieved successfully',
                data: approvals,
                total: approvals.length,
            };
        } catch (error) {
            logger.error('Failed to retrieve course approvals', { error });
            throw error;
        }
    }



    static async searchInstructors(input: SearchInstructorInput): Promise<SearchInstructorResponse> {
        try {
            const decoded = jwt.verify(input.token, config.jwt.secret) as { id: number };

            // Get existing instructors in the course
            const existingInstructors = await prisma.courseInstructor.findMany({
                where: { course_id: input.course_id },
                select: { user_id: true },
            });
            const existingInstructorIds = existingInstructors.map(i => i.user_id);

            // Search all instructors by email or username, excluding self and existing course instructors
            const users = await prisma.user.findMany({
                where: {
                    OR: [
                        { email: { contains: input.query, mode: 'insensitive' } },
                        { username: { contains: input.query, mode: 'insensitive' } },
                    ],
                    role: { code: 'INSTRUCTOR' },
                    id: {
                        notIn: [decoded.id, ...existingInstructorIds],
                    },
                },
                include: {
                    profile: true
                },
                take: 10
            });

            const results = await Promise.all(users.map(async (user) => {
                let avatar_url: string | null = null;
                if (user.profile?.avatar_url) {
                    try {
                        avatar_url = await getPresignedUrl(user.profile.avatar_url, 3600);
                    } catch (err) {
                        logger.warn(`Failed to generate presigned URL for avatar: ${err}`);
                    }
                }
                return {
                    id: user.id,
                    username: user.username,
                    email: user.email,
                    first_name: user.profile?.first_name || null,
                    last_name: user.profile?.last_name || null,
                    avatar_url,
                };
            }));

            return {
                code: 200,
                message: 'Instructors found',
                data: results,
            };
        } catch (error) {
            logger.error('Failed to search instructors', { error });
            throw error;
        }
    }

    static async addInstructorToCourse(addinstructorCourse: addinstructorCourse): Promise<addinstructorCourseResponse> {
        try {
            // Validate user is instructor of this course
            await this.validateCourseInstructor(addinstructorCourse.token, addinstructorCourse.course_id);

            // Find user by email or username
            const user = await prisma.user.findFirst({
                where: {
                    OR: [
                        { email: addinstructorCourse.email_or_username },
                        { username: addinstructorCourse.email_or_username },
                    ],
                    role: { code: 'INSTRUCTOR' }
                }
            });

            if (!user) {
                throw new NotFoundError('Instructor not found with this email or username');
            }

            // Check if already added
            const existing = await prisma.courseInstructor.findUnique({
                where: {
                    course_id_user_id: {
                        course_id: addinstructorCourse.course_id,
                        user_id: user.id,
                    }
                }
            });

            if (existing) {
                throw new ValidationError('This instructor is already added to the course');
            }

            await prisma.courseInstructor.create({
                data: {
                    course_id: addinstructorCourse.course_id,
                    user_id: user.id,
                }
            });

            return {
                code: 200,
                message: 'Instructor added to course successfully',
            };
        } catch (error) {
            logger.error('Failed to add instructor to course', { error });
            throw error;
        }
    }

    static async removeInstructorFromCourse(removeinstructorCourse: removeinstructorCourse): Promise<removeinstructorCourseResponse> {
        try {
            const decoded = jwt.verify(removeinstructorCourse.token, config.jwt.secret) as { id: number; type: string };
            await prisma.courseInstructor.delete({
                where: {
                    course_id_user_id: {
                        course_id: removeinstructorCourse.course_id,
                        user_id: removeinstructorCourse.user_id,
                    },
                }
            });
            return {
                code: 200,
                message: 'Instructor removed from course successfully',
            };
        } catch (error) {
            logger.error('Failed to remove instructor from course', { error });
            throw error;
        }
    }

    static async listInstructorsOfCourse(listinstructorCourse: listinstructorCourse): Promise<listinstructorCourseResponse> {
        try {
            const decoded = jwt.verify(listinstructorCourse.token, config.jwt.secret) as { id: number; type: string };
            const courseInstructors = await prisma.courseInstructor.findMany({
                where: {
                    course_id: listinstructorCourse.course_id,
                },
                include: {
                    user: {
                        include: {
                            profile: true
                        }
                    },
                }
            });

            const data = await Promise.all(courseInstructors.map(async (ci) => {
                let avatar_url: string | null = null;
                if (ci.user.profile?.avatar_url) {
                    try {
                        avatar_url = await getPresignedUrl(ci.user.profile.avatar_url, 3600);
                    } catch (err) {
                        logger.warn(`Failed to generate presigned URL for avatar: ${err}`);
                    }
                }
                return {
                    user_id: ci.user_id,
                    is_primary: ci.is_primary,
                    user: {
                        id: ci.user.id,
                        username: ci.user.username,
                        email: ci.user.email,
                        first_name: ci.user.profile?.first_name || null,
                        last_name: ci.user.profile?.last_name || null,
                        avatar_url,
                    },
                };
            }));

            return {
                code: 200,
                message: 'Instructors retrieved successfully',
                data,
            };
        } catch (error) {
            logger.error('Failed to retrieve instructors of course', { error });
            throw error;
        }
    }

    static async setPrimaryInstructor(setprimaryCourseInstructor: setprimaryCourseInstructor): Promise<setprimaryCourseInstructorResponse> {
        try {
            const decoded = jwt.verify(setprimaryCourseInstructor.token, config.jwt.secret) as { id: number; type: string };
            await prisma.courseInstructor.update({
                where: {
                    course_id_user_id: {
                        course_id: setprimaryCourseInstructor.course_id,
                        user_id: setprimaryCourseInstructor.user_id,
                    },
                },
                data: {
                    is_primary: true,
                }
            });
            return {
                code: 200,
                message: 'Primary instructor set successfully',
            };
        } catch (error) {
            logger.error('Failed to set primary instructor', { error });
            throw error;
        }
    }

    static async validateCourseInstructor(token: string, courseId: number): Promise<{ user_id: number; is_primary: boolean }> {
        const decoded = jwt.verify(token, config.jwt.secret) as { id: number; type: string };
        const courseInstructor = await prisma.courseInstructor.findFirst({
            where: {
                user_id: decoded.id,
                course_id: courseId
            }
        });

        if (!courseInstructor) {
            throw new ForbiddenError('You are not an instructor of this course');
        } else return { user_id: courseInstructor.user_id, is_primary: courseInstructor.is_primary };
    }

    static async validateCourseStatus(courseId: number): Promise<void> {
        const course = await prisma.course.findUnique({ where: { id: courseId } });
        if (!course) {
            throw new NotFoundError('Course not found');
        }
        if (course.status === 'APPROVED' || course.status === 'PENDING') {
            throw new ForbiddenError('Course is already approved Cannot Edit');
        }
    }

    /**
     * ดึงรายชื่อนักเรียนที่ลงทะเบียนในคอร์สพร้อม progress
     * Get all enrolled students with their progress
     */
    static async getEnrolledStudents(input: GetEnrolledStudentsInput): Promise<GetEnrolledStudentsResponse> {
        try {
            const { token, course_id, page = 1, limit = 20, search, status } = input;
            const decoded = jwt.verify(token, config.jwt.secret) as { id: number };

            // Validate instructor
            await this.validateCourseInstructor(token, course_id);

            // Build where clause
            const whereClause: any = { course_id };

            // Add status filter
            if (status) {
                whereClause.status = status;
            }

            // Add search filter
            if (search) {
                whereClause.OR = [
                    { user: { username: { contains: search, mode: 'insensitive' } } },
                    { user: { email: { contains: search, mode: 'insensitive' } } },
                    { user: { profile: { first_name: { contains: search, mode: 'insensitive' } } } },
                    { user: { profile: { last_name: { contains: search, mode: 'insensitive' } } } },
                ];
            }

            // Get enrollments with user data
            const skip = (page - 1) * limit;
            const [enrollments, total] = await Promise.all([
                prisma.enrollment.findMany({
                    where: whereClause,
                    include: {
                        user: {
                            include: {
                                profile: true,
                            },
                        },
                    },
                    orderBy: { enrolled_at: 'desc' },
                    skip,
                    take: limit,
                }),
                prisma.enrollment.count({ where: whereClause }),
            ]);

            // Format response with presigned URLs for avatars
            const studentsData = await Promise.all(
                enrollments.map(async (enrollment) => {
                    let avatarUrl: string | null = null;
                    if (enrollment.user.profile?.avatar_url) {
                        try {
                            avatarUrl = await getPresignedUrl(enrollment.user.profile.avatar_url, 3600);
                        } catch (err) {
                            logger.warn(`Failed to generate presigned URL for avatar: ${err}`);
                        }
                    }

                    return {
                        user_id: enrollment.user.id,
                        username: enrollment.user.username,
                        email: enrollment.user.email,
                        first_name: enrollment.user.profile?.first_name || null,
                        last_name: enrollment.user.profile?.last_name || null,
                        avatar_url: avatarUrl,
                        enrolled_at: enrollment.enrolled_at,
                        progress_percentage: Number(enrollment.progress_percentage) || 0,
                        status: enrollment.status,
                    };
                })
            );

            return {
                code: 200,
                message: 'Enrolled students retrieved successfully',
                data: studentsData,
                total,
                page,
                limit,
            };
        } catch (error) {
            logger.error(`Error getting enrolled students: ${error}`);
            throw error;
        }
    }

    /**
     * ดึงคะแนนสอบของนักเรียนทุกคนในแต่ละ lesson quiz
     * Get quiz scores of all students for a specific lesson
     */
    static async getQuizScores(input: GetQuizScoresInput): Promise<GetQuizScoresResponse> {
        try {
            const { token, course_id, lesson_id, page = 1, limit = 20, search, is_passed } = input;
            const decoded = jwt.verify(token, config.jwt.secret) as { id: number };

            // Validate instructor
            await this.validateCourseInstructor(token, course_id);

            // Get lesson and verify it's a QUIZ type
            const lesson = await prisma.lesson.findUnique({
                where: { id: lesson_id },
                include: {
                    quiz: {
                        include: {
                            questions: true,
                        },
                    },
                    chapter: true,
                },
            });

            if (!lesson) {
                throw new NotFoundError('Lesson not found');
            }

            if (lesson.type !== 'QUIZ') {
                throw new ValidationError('This lesson is not a quiz');
            }

            if (!lesson.quiz) {
                throw new NotFoundError('Quiz not found for this lesson');
            }

            // Verify lesson belongs to the course
            if (lesson.chapter.course_id !== course_id) {
                throw new NotFoundError('Lesson not found in this course');
            }

            // Calculate total score from questions
            const totalScore = lesson.quiz.questions.reduce((sum, q) => sum + q.score, 0);

            // Get all enrolled students who have attempted this quiz
            const skip = (page - 1) * limit;
            
            // Get unique users who attempted this quiz
            const quizAttempts = await prisma.quizAttempt.findMany({
                where: { quiz_id: lesson.quiz.id },
                include: {
                    user: {
                        include: {
                            profile: true,
                        },
                    },
                },
                orderBy: { completed_at: 'desc' },
            });

            // Group attempts by user
            const userAttemptsMap = new Map<number, typeof quizAttempts>();
            for (const attempt of quizAttempts) {
                const userId = attempt.user_id;
                if (!userAttemptsMap.has(userId)) {
                    userAttemptsMap.set(userId, []);
                }
                userAttemptsMap.get(userId)!.push(attempt);
            }

            // Get unique users and apply filters
            let filteredUserIds = Array.from(userAttemptsMap.keys());

            // Apply search filter
            if (search) {
                filteredUserIds = filteredUserIds.filter(userId => {
                    const userAttempts = userAttemptsMap.get(userId)!;
                    const user = userAttempts[0].user;
                    const searchLower = search.toLowerCase();
                    return (
                        user.username.toLowerCase().includes(searchLower) ||
                        user.email.toLowerCase().includes(searchLower) ||
                        (user.profile?.first_name?.toLowerCase().includes(searchLower)) ||
                        (user.profile?.last_name?.toLowerCase().includes(searchLower))
                    );
                });
            }

            // Apply is_passed filter
            if (is_passed !== undefined) {
                filteredUserIds = filteredUserIds.filter(userId => {
                    const userAttempts = userAttemptsMap.get(userId)!;
                    const userIsPassed = userAttempts.some(a => a.is_passed);
                    return userIsPassed === is_passed;
                });
            }

            // Paginate
            const total = filteredUserIds.length;
            const paginatedUserIds = filteredUserIds.slice(skip, skip + limit);

            // Format response
            const studentsData = await Promise.all(
                paginatedUserIds.map(async (userId) => {
                    const userAttempts = userAttemptsMap.get(userId)!;
                    const user = userAttempts[0].user;

                    let avatarUrl: string | null = null;
                    if (user.profile?.avatar_url) {
                        try {
                            avatarUrl = await getPresignedUrl(user.profile.avatar_url, 3600);
                        } catch (err) {
                            logger.warn(`Failed to generate presigned URL for avatar: ${err}`);
                        }
                    }

                    // Get latest attempt (sorted by attempt_number desc, first one is latest)
                    const latestAttempt = userAttempts[0];

                    const bestScore = Math.max(...userAttempts.map(a => a.score));
                    const isPassed = userAttempts.some(a => a.is_passed);

                    return {
                        user_id: user.id,
                        username: user.username,
                        email: user.email,
                        first_name: user.profile?.first_name || null,
                        last_name: user.profile?.last_name || null,
                        avatar_url: avatarUrl,
                        latest_attempt: latestAttempt ? {
                            id: latestAttempt.id,
                            score: latestAttempt.score,
                            total_score: totalScore,
                            is_passed: latestAttempt.is_passed,
                            attempt_number: latestAttempt.attempt_number,
                            completed_at: latestAttempt.completed_at,
                        } : null,
                        best_score: bestScore,
                        total_attempts: userAttempts.length,
                        is_passed: isPassed,
                    };
                })
            );

            return {
                code: 200,
                message: 'Quiz scores retrieved successfully',
                data: {
                    lesson_id: lesson.id,
                    lesson_title: lesson.title as { th: string; en: string },
                    quiz_id: lesson.quiz.id,
                    quiz_title: lesson.quiz.title as { th: string; en: string },
                    passing_score: lesson.quiz.passing_score,
                    total_score: totalScore,
                    students: studentsData,
                },
                total,
                page,
                limit,
            };
        } catch (error) {
            logger.error(`Error getting quiz scores: ${error}`);
            throw error;
        }
    }

    /**
     * ดูรายละเอียดการทำข้อสอบของนักเรียนแต่ละคน
     * Get quiz attempt detail for a specific student
     */
    static async getQuizAttemptDetail(input: GetQuizAttemptDetailInput): Promise<GetQuizAttemptDetailResponse> {
        try {
            const { token, course_id, lesson_id, student_id } = input;
            const decoded = jwt.verify(token, config.jwt.secret) as { id: number };

            // Validate instructor
            await this.validateCourseInstructor(token, course_id);

            // Get lesson and verify it's a QUIZ type
            const lesson = await prisma.lesson.findUnique({
                where: { id: lesson_id },
                include: {
                    quiz: {
                        include: {
                            questions: {
                                include: {
                                    choices: true,
                                },
                                orderBy: { sort_order: 'asc' },
                            },
                        },
                    },
                    chapter: true,
                },
            });

            if (!lesson) throw new NotFoundError('Lesson not found');
            if (lesson.type !== 'QUIZ') throw new ValidationError('This lesson is not a quiz');
            if (!lesson.quiz) throw new NotFoundError('Quiz not found for this lesson');
            if (lesson.chapter.course_id !== course_id) throw new NotFoundError('Lesson not found in this course');

            // Get student info
            const student = await prisma.user.findUnique({
                where: { id: student_id },
                include: { profile: true },
            });

            if (!student) throw new NotFoundError('Student not found');

            // Get latest quiz attempt
            const quizAttempt = await prisma.quizAttempt.findFirst({
                where: {
                    user_id: student_id,
                    quiz_id: lesson.quiz.id,
                },
                orderBy: { attempt_number: 'desc' },
            });

            if (!quizAttempt) throw new NotFoundError('Quiz attempt not found');

            // Calculate total score from questions
            const totalScore = lesson.quiz.questions.reduce((sum, q) => sum + q.score, 0);

            // Parse answers from quiz attempt
            const studentAnswers = (quizAttempt.answers as any[]) || [];

            // Build answers review
            const answersReview = lesson.quiz.questions.map(question => {
                const studentAnswer = studentAnswers.find((a: any) => a.question_id === question.id);
                const selectedChoiceId = studentAnswer?.choice_id || null;
                const selectedChoice = selectedChoiceId ? question.choices.find(c => c.id === selectedChoiceId) : null;

                // Check if selected choice is correct from Choice model
                const isCorrect = selectedChoice?.is_correct || false;
                // Score is question.score if correct, otherwise 0
                const earnedScore = isCorrect ? question.score : 0;

                return {
                    question_id: question.id,
                    sort_order: question.sort_order,
                    question_text: question.question as { th: string; en: string },
                    selected_choice_id: selectedChoiceId,
                    selected_choice_text: selectedChoice ? selectedChoice.text as { th: string; en: string } : null,
                    is_correct: isCorrect,
                    score: earnedScore,
                    question_score: question.score,
                };
            });

            return {
                code: 200,
                message: 'Quiz attempt detail retrieved successfully',
                data: {
                    attempt_id: quizAttempt.id,
                    quiz_id: quizAttempt.quiz_id,
                    student: {
                        user_id: student.id,
                        username: student.username,
                        email: student.email,
                        first_name: student.profile?.first_name || null,
                        last_name: student.profile?.last_name || null,
                    },
                    score: quizAttempt.score,
                    total_score: totalScore,
                    total_questions: quizAttempt.total_questions,
                    correct_answers: quizAttempt.correct_answers,
                    is_passed: quizAttempt.is_passed,
                    passing_score: lesson.quiz.passing_score,
                    attempt_number: quizAttempt.attempt_number,
                    started_at: quizAttempt.started_at,
                    completed_at: quizAttempt.completed_at,
                    answers_review: answersReview,
                },
            };
        } catch (error) {
            logger.error(`Error getting quiz attempt detail: ${error}`);
            throw error;
        }
    }

    /**
     * ดึงรายละเอียดการเรียนของนักเรียนแต่ละคน
     * Get enrolled student detail with lesson progress
     */
    static async getEnrolledStudentDetail(input: GetEnrolledStudentDetailInput): Promise<GetEnrolledStudentDetailResponse> {
        try {
            const { token, course_id, student_id } = input;

            // Validate instructor
            await this.validateCourseInstructor(token, course_id);

            // Get student info
            const student = await prisma.user.findUnique({
                where: { id: student_id },
                include: { profile: true },
            });

            if (!student) throw new NotFoundError('Student not found');

            // Get enrollment
            const enrollment = await prisma.enrollment.findUnique({
                where: {
                    unique_enrollment: {
                        user_id: student_id,
                        course_id,
                    },
                },
            });

            if (!enrollment) throw new NotFoundError('Student is not enrolled in this course');

            // Get course with chapters and lessons
            const course = await prisma.course.findUnique({
                where: { id: course_id },
                include: {
                    chapters: {
                        orderBy: { sort_order: 'asc' },
                        include: {
                            lessons: {
                                orderBy: { sort_order: 'asc' },
                            },
                        },
                    },
                },
            });

            if (!course) throw new NotFoundError('Course not found');

            // Get all lesson progress for this student in this course
            const lessonIds = course.chapters.flatMap(ch => ch.lessons.map(l => l.id));
            const lessonProgressList = await prisma.lessonProgress.findMany({
                where: {
                    user_id: student_id,
                    lesson_id: { in: lessonIds },
                },
            });

            // Create a map for quick lookup
            const progressMap = new Map(lessonProgressList.map(p => [p.lesson_id, p]));

            // Build chapters with lesson progress
            let totalCompletedLessons = 0;
            let totalLessons = 0;

            const chaptersData = course.chapters.map(chapter => {
                const lessonsData = chapter.lessons.map(lesson => {
                    const progress = progressMap.get(lesson.id);
                    totalLessons++;

                    if (progress?.is_completed) {
                        totalCompletedLessons++;
                    }

                    return {
                        lesson_id: lesson.id,
                        lesson_title: lesson.title as { th: string; en: string },
                        lesson_type: lesson.type,
                        sort_order: lesson.sort_order,
                        is_completed: progress?.is_completed || false,
                        completed_at: progress?.completed_at || null,
                        video_progress_seconds: progress?.video_progress_seconds || null,
                        video_duration_seconds: progress?.video_duration_seconds || null,
                        video_progress_percentage: progress?.video_progress_percentage ? Number(progress.video_progress_percentage) : null,
                        last_watched_at: progress?.last_watched_at || null,
                    };
                });

                const completedLessons = lessonsData.filter(l => l.is_completed).length;

                return {
                    chapter_id: chapter.id,
                    chapter_title: chapter.title as { th: string; en: string },
                    sort_order: chapter.sort_order,
                    lessons: lessonsData,
                    completed_lessons: completedLessons,
                    total_lessons: lessonsData.length,
                };
            });

            // Get avatar URL
            let avatarUrl: string | null = null;
            if (student.profile?.avatar_url) {
                try {
                    avatarUrl = await getPresignedUrl(student.profile.avatar_url, 3600);
                } catch (err) {
                    logger.warn(`Failed to generate presigned URL for avatar: ${err}`);
                }
            }

            return {
                code: 200,
                message: 'Enrolled student detail retrieved successfully',
                data: {
                    student: {
                        user_id: student.id,
                        username: student.username,
                        email: student.email,
                        first_name: student.profile?.first_name || null,
                        last_name: student.profile?.last_name || null,
                        avatar_url: avatarUrl,
                    },
                    enrollment: {
                        enrolled_at: enrollment.enrolled_at,
                        progress_percentage: Number(enrollment.progress_percentage) || 0,
                        status: enrollment.status,
                    },
                    chapters: chaptersData,
                    total_completed_lessons: totalCompletedLessons,
                    total_lessons: totalLessons,
                },
            };
        } catch (error) {
            logger.error(`Error getting enrolled student detail: ${error}`);
            throw error;
        }
    }
}
