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 {
    EnrollCourseInput,
    EnrollCourseResponse,
    ListEnrolledCoursesInput,
    ListEnrolledCoursesResponse,
    GetCourseLearningInput,
    GetCourseLearningResponse,
    GetLessonContentInput,
    GetLessonContentResponse,
    CheckLessonAccessInput,
    CheckLessonAccessResponse,
    SaveVideoProgressInput,
    SaveVideoProgressResponse,
    GetVideoProgressInput,
    GetVideoProgressResponse,
    CompleteLessonInput,
    CompleteLessonResponse,
    SubmitQuizInput,
    SubmitQuizResponse,
    GetQuizAttemptsInput,
    GetQuizAttemptsResponse,
} from "../types/CoursesStudent.types";
import { getPresignedUrl, listObjects, getVideoFolder, getAttachmentsFolder } from '../config/minio';


export class CoursesStudentService {
    /**
     * Mark lesson as complete and update enrollment progress
     * Shared function for submitQuiz, saveVideoProgress, completeLesson
     */
    private async markLessonComplete(userId: number, lessonId: number, courseId: number): Promise<{
        lessonProgress: { lesson_id: number; is_completed: boolean; completed_at: Date | null };
        enrollmentProgress: { progress_percentage: number; is_course_completed: boolean };
    }> {
        const now = new Date();

        // Upsert lesson progress
        const lessonProgress = await prisma.lessonProgress.upsert({
            where: {
                user_id_lesson_id: {
                    user_id: userId,
                    lesson_id: lessonId,
                },
            },
            create: {
                user_id: userId,
                lesson_id: lessonId,
                is_completed: true,
                completed_at: now,
            },
            update: {
                is_completed: true,
                completed_at: now,
            },
        });

        // Get all lessons in the course
        const course = await prisma.course.findUnique({
            where: { id: courseId },
            include: {
                chapters: {
                    include: {
                        lessons: {
                            where: { is_published: true },
                            select: { id: true },
                        },
                    },
                },
            },
        });

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

        const allLessonIds = course.chapters.flatMap(ch => ch.lessons.map(l => l.id));
        const totalLessons = allLessonIds.length;

        // Count completed lessons
        const completedLessons = await prisma.lessonProgress.count({
            where: {
                user_id: userId,
                lesson_id: { in: allLessonIds },
                is_completed: true,
            },
        });

        // Calculate progress percentage
        const progressPercentage = totalLessons > 0
            ? Math.round((completedLessons / totalLessons) * 100)
            : 0;

        const isCourseCompleted = completedLessons >= totalLessons;

        // Update enrollment
        await prisma.enrollment.update({
            where: {
                unique_enrollment: {
                    user_id: userId,
                    course_id: courseId,
                },
            },
            data: {
                progress_percentage: progressPercentage,
                ...(isCourseCompleted ? {
                    status: 'COMPLETED',
                    completed_at: now,
                } : {}),
            },
        });

        return {
            lessonProgress: {
                lesson_id: lessonProgress.lesson_id,
                is_completed: lessonProgress.is_completed,
                completed_at: lessonProgress.completed_at,
            },
            enrollmentProgress: {
                progress_percentage: progressPercentage,
                is_course_completed: isCourseCompleted,
            },
        };
    }

    async enrollCourse(input: EnrollCourseInput): Promise<EnrollCourseResponse> {
        try {
            const { course_id } = input;
            const decoded = jwt.verify(input.token, config.jwt.secret) as { id: number; type: string };

            const course = await prisma.course.findUnique({
                where: { id: course_id },
            });

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

            if (course.status !== 'APPROVED') throw new ForbiddenError('Cannot enroll in this course. Course is not available.');

            const existingEnrollment = await prisma.enrollment.findUnique({
                where: {
                    unique_enrollment: {
                        user_id: decoded.id,
                        course_id,
                    },
                },
            });

            if (existingEnrollment) {
                throw new ValidationError('Already enrolled in this course');
            }

            const enrollment = await prisma.enrollment.create({
                data: {
                    course_id,
                    user_id: decoded.id,
                    status: 'ENROLLED',
                    enrolled_at: new Date(),
                },
            });
            return {
                code: 200,
                message: 'Enrollment successful',
                data: {
                    enrollment_id: enrollment.id,
                    course_id: enrollment.course_id,
                    user_id: enrollment.user_id,
                    status: enrollment.status,
                    enrolled_at: enrollment.enrolled_at,
                },
            };
        } catch (error) {
            logger.error(error);
            throw error;
        }
    }

    async GetEnrolledCourses(input: ListEnrolledCoursesInput): Promise<ListEnrolledCoursesResponse> {
        try {
            const { token } = input;
            const page = input.page ?? 1;
            const limit = input.limit ?? 20;
            const decoded = jwt.verify(token, config.jwt.secret) as { id: number; type: string };
            const enrollments = await prisma.enrollment.findMany({
                where: {
                    user_id: decoded.id,
                },
                include: {
                    course: {
                        select: {
                            id: true,
                            title: true,
                            slug: true,
                            thumbnail_url: true,
                            description: true,
                        }
                    }
                },
                skip: (page - 1) * limit,
                take: limit,
            });
            const total = await prisma.enrollment.count({
                where: {
                    user_id: decoded.id,
                },
            });

            const data = await Promise.all(
                enrollments.map(async (enrollment) => {
                    let thumbnail_presigned_url: string | null = null;
                    if (enrollment.course.thumbnail_url) {
                        try {
                            thumbnail_presigned_url = await getPresignedUrl(enrollment.course.thumbnail_url, 3600);
                        } catch (err) {
                            logger.warn(`Failed to generate presigned URL for thumbnail: ${err}`);
                        }
                    }
                    return {
                        id: enrollment.id,
                        course_id: enrollment.course_id,
                        course: {
                            id: enrollment.course.id,
                            title: enrollment.course.title as { th: string; en: string },
                            slug: enrollment.course.slug,
                            thumbnail_url: thumbnail_presigned_url,
                            description: enrollment.course.description as { th: string; en: string },
                        },
                        status: enrollment.status,
                        progress_percentage: enrollment.progress_percentage,
                        enrolled_at: enrollment.enrolled_at,
                        started_at: enrollment.started_at,
                        completed_at: enrollment.completed_at,
                        last_accessed_at: enrollment.last_accessed_at,
                    };
                })
            );

            return {
                code: 200,
                message: 'Enrollments retrieved successfully',
                data,
                total,
                page,
                limit,
            };
        } catch (error) {
            logger.error(error);
            throw error;
        }
    }
    async getCourseLearning(input: GetCourseLearningInput): Promise<GetCourseLearningResponse> {
        try {
            const { token, course_id } = input;
            const decoded = jwt.verify(token, config.jwt.secret) as { id: number; type: string };

            // Get course with chapters and lessons (basic info only)
            const course = await prisma.course.findUnique({
                where: { id: course_id },
                include: {
                    chapters: {
                        where: { is_published: true },
                        orderBy: { sort_order: 'asc' },
                        include: {
                            lessons: {
                                where: { is_published: true },
                                orderBy: { sort_order: 'asc' },
                                select: {
                                    id: true,
                                    chapter_id: true,
                                    title: true,
                                    type: true,
                                    duration_minutes: true,
                                    sort_order: true,
                                    is_published: true,
                                    is_sequential: true,
                                    prerequisite_lesson_ids: true,
                                    require_pass_quiz: true,
                                },
                            },
                        },
                    },
                },
            });

            if (!course) {
                throw new ForbiddenError('Course not found');
            }

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

            if (!enrollment) {
                throw new ForbiddenError('You are not enrolled in this course');
            }

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

            const progressMap = new Map(lessonProgress.map(p => [p.lesson_id, p]));

            // Build chapters with lesson lock status
            const chapters = course.chapters.map(chapter => ({
                id: chapter.id,
                title: chapter.title as { th: string; en: string },
                description: chapter.description as { th: string; en: string } | null,
                sort_order: chapter.sort_order,
                is_published: chapter.is_published,
                lessons: chapter.lessons.map(lesson => {
                    const progress = progressMap.get(lesson.id);
                    const isCompleted = progress?.is_completed ?? false;

                    // Check lock status
                    let isLocked = false;
                    let lockReason: string | undefined;

                    if (lesson.is_sequential) {
                        const prereqIds = lesson.prerequisite_lesson_ids as number[] | null;
                        if (prereqIds && prereqIds.length > 0) {
                            const allPrereqCompleted = prereqIds.every(id => {
                                const prereqProgress = progressMap.get(id);
                                return prereqProgress?.is_completed;
                            });
                            if (!allPrereqCompleted) {
                                isLocked = true;
                                lockReason = 'Complete prerequisite lessons first';
                            }
                        }
                    }

                    return {
                        id: lesson.id,
                        chapter_id: lesson.chapter_id,
                        title: lesson.title as { th: string; en: string },
                        type: lesson.type as 'VIDEO' | 'QUIZ',
                        duration_minutes: lesson.duration_minutes,
                        sort_order: lesson.sort_order,
                        is_published: lesson.is_published,
                        is_sequential: lesson.is_sequential,
                        prerequisite_lesson_ids: lesson.prerequisite_lesson_ids as number[] | null,
                        require_pass_quiz: lesson.require_pass_quiz,
                        // Lock status
                        is_locked: isLocked,
                        lock_reason: lockReason,
                        // Progress
                        is_completed: isCompleted,
                        video_progress_percentage: progress?.video_progress_percentage ? Number(progress.video_progress_percentage) : undefined,
                    };
                }),
            }));

            const total_lessons = lessonIds.length;
            const completed_lessons = lessonProgress.filter(p => p.is_completed).length;

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

            return {
                code: 200,
                message: 'Course learning retrieved successfully',
                data: {
                    course: {
                        id: course.id,
                        title: course.title as { th: string; en: string },
                        slug: course.slug,
                        description: course.description as { th: string; en: string },
                        thumbnail_url: thumbnail_presigned_url,
                        have_certificate: course.have_certificate,
                    },
                    enrollment: {
                        status: enrollment.status,
                        progress_percentage: enrollment.progress_percentage,
                        enrolled_at: enrollment.enrolled_at,
                        started_at: enrollment.started_at,
                        completed_at: enrollment.completed_at,
                    },
                    chapters,
                    total_lessons,
                    completed_lessons,
                },
            };
        } catch (error) {
            logger.error(error);
            throw error;
        }
    }

    async getlessonContent(input: GetLessonContentInput): Promise<GetLessonContentResponse> {
        try {
            const { token, course_id, lesson_id } = input;
            const decoded = jwt.verify(token, config.jwt.secret) as { id: number; type: string };

            // Import MinIO functions

            // Check enrollment
            const enrollment = await prisma.enrollment.findUnique({
                where: {
                    unique_enrollment: {
                        user_id: decoded.id,
                        course_id,
                    },
                },
            });

            if (!enrollment) {
                throw new ForbiddenError('You are not enrolled in this course');
            }

            // Get lesson with attachments and quiz (including questions and choices)
            const lesson = await prisma.lesson.findUnique({
                where: { id: lesson_id },
                include: {
                    attachments: {
                        orderBy: { sort_order: 'asc' },
                    },
                    quiz: {
                        include: {
                            questions: {
                                orderBy: { sort_order: 'asc' },
                                include: {
                                    choices: {
                                        orderBy: { sort_order: 'asc' },
                                    },
                                },
                            },
                        },
                    },
                    chapter: {
                        include: {
                            lessons: {
                                where: { is_published: true },
                                orderBy: { sort_order: 'asc' },
                                select: { id: true, sort_order: true },
                            },
                        },
                    },
                },
            });

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

            // Get user's progress for this lesson
            const lessonProgress = await prisma.lessonProgress.findUnique({
                where: {
                    user_id_lesson_id: {
                        user_id: decoded.id,
                        lesson_id,
                    },
                },
            });

            // Calculate prev/next lesson IDs
            const allLessons = lesson.chapter.lessons;
            const currentIndex = allLessons.findIndex(l => l.id === lesson_id);
            const prevLessonId = currentIndex > 0 ? allLessons[currentIndex - 1].id : null;
            const nextLessonId = currentIndex < allLessons.length - 1 ? allLessons[currentIndex + 1].id : null;

            // Get course_id from chapter
            const chapter_course_id = lesson.chapter.course_id;

            // Import additional MinIO functions
            // Using MinIO functions imported above

            // Get video URL - check for YouTube or MinIO
            let video_url: string | null = null;
            const videoAttachment = await prisma.lessonAttachment.findFirst({
                where: { lesson_id, sort_order: 0 }
            });

            if (videoAttachment) {
                if (videoAttachment.mime_type === 'video/youtube') {
                    // YouTube video - build URL from video ID stored in file_path
                    video_url = `https://www.youtube.com/watch?v=${videoAttachment.file_path}`;
                } else {
                    // MinIO video - get presigned URL
                    try {
                        video_url = await getPresignedUrl(videoAttachment.file_path, 3600);
                    } catch (err) {
                        logger.error(`Failed to get video from MinIO: ${err}`);
                    }
                }
            } else {
                // Fallback: try to get video from MinIO folder (legacy support)
                try {
                    const videoPrefix = getVideoFolder(chapter_course_id, lesson_id);
                    const videoFiles = await listObjects(videoPrefix);
                    if (videoFiles.length > 0) {
                        video_url = await getPresignedUrl(videoFiles[0].name, 3600);
                    }
                } catch (err) {
                    logger.error(`Failed to get video from MinIO: ${err}`);
                }
            }

            // Get attachments from MinIO folder
            const attachmentsWithUrls: {
                file_name: string;
                file_path: string;
                file_size: number;
                mime_type: string;
                presigned_url: string | null;
            }[] = [];

            try {
                const attachmentsPrefix = getAttachmentsFolder(chapter_course_id, lesson_id);
                const attachmentFiles = await listObjects(attachmentsPrefix);

                for (const file of attachmentFiles) {
                    let presigned_url: string | null = null;
                    try {
                        presigned_url = await getPresignedUrl(file.name, 3600);
                    } catch (err) {
                        logger.error(`Failed to generate presigned URL for ${file.name}: ${err}`);
                    }

                    // Extract filename from path
                    const fileName = file.name.split('/').pop() || file.name;
                    // Guess mime type from extension
                    const ext = fileName.split('.').pop()?.toLowerCase() || '';
                    const mimeTypes: { [key: string]: string } = {
                        'pdf': 'application/pdf',
                        'doc': 'application/msword',
                        'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
                        'ppt': 'application/vnd.ms-powerpoint',
                        'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
                        'xls': 'application/vnd.ms-excel',
                        'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
                        'png': 'image/png',
                        'jpg': 'image/jpeg',
                        'jpeg': 'image/jpeg',
                        'gif': 'image/gif',
                        'mp4': 'video/mp4',
                        'zip': 'application/zip',
                    };
                    const mime_type = mimeTypes[ext] || 'application/octet-stream';

                    attachmentsWithUrls.push({
                        file_name: fileName,
                        file_path: file.name,
                        file_size: file.size,
                        mime_type,
                        presigned_url,
                    });
                }
            } catch (err) {
                logger.error(`Failed to list attachments from MinIO: ${err}`);
            }


            return {
                code: 200,
                message: 'Lesson retrieved successfully',
                data: {
                    id: lesson.id,
                    chapter_id: lesson.chapter_id,
                    title: lesson.title as { th: string; en: string },
                    content: lesson.content as { th: string; en: string } | null,
                    type: lesson.type as 'VIDEO' | 'QUIZ',
                    duration_minutes: lesson.duration_minutes,
                    is_sequential: lesson.is_sequential,
                    prerequisite_lesson_ids: lesson.prerequisite_lesson_ids as number[] | null,
                    require_pass_quiz: lesson.require_pass_quiz,
                    video_url, // Presigned URL for video
                    attachments: attachmentsWithUrls,
                    quiz: lesson.quiz ? {
                        id: lesson.quiz.id,
                        title: lesson.quiz.title as { th: string; en: string },
                        description: lesson.quiz.description as { th: string; en: string } | null,
                        passing_score: lesson.quiz.passing_score,
                        time_limit: lesson.quiz.time_limit,
                        shuffle_questions: lesson.quiz.shuffle_questions,
                        shuffle_choices: lesson.quiz.shuffle_choices,
                        is_skippable: lesson.quiz.is_skippable,
                        show_answers_after_completion: lesson.quiz.show_answers_after_completion,
                        questions: lesson.quiz.questions.map(q => ({
                            id: q.id,
                            question: q.question as { th: string; en: string },
                            question_type: q.question_type,
                            score: q.score,
                            sort_order: q.sort_order,
                            choices: q.choices.map(c => ({
                                id: c.id,
                                text: c.text as { th: string; en: string },
                                sort_order: c.sort_order,
                            })),
                        })),
                    } : null,
                    prev_lesson_id: prevLessonId,
                    next_lesson_id: nextLessonId,
                },
                progress: lessonProgress ? {
                    is_completed: lessonProgress.is_completed,
                    video_progress_seconds: lessonProgress.video_progress_seconds,
                    video_duration_seconds: lessonProgress.video_duration_seconds,
                    video_progress_percentage: lessonProgress.video_progress_percentage ? Number(lessonProgress.video_progress_percentage) : null,
                    last_watched_at: lessonProgress.last_watched_at,
                } : undefined,
            };
        } catch (error) {
            logger.error(error);
            throw error;
        }
    }


    async checkAccessLesson(input: CheckLessonAccessInput): Promise<CheckLessonAccessResponse> {
        try {
            const { token, course_id, lesson_id } = input;
            const decoded = jwt.verify(token, config.jwt.secret) as { id: number; type: string };

            // Check enrollment
            const enrollment = await prisma.enrollment.findUnique({
                where: {
                    unique_enrollment: {
                        user_id: decoded.id,
                        course_id,
                    },
                },
            });

            if (!enrollment) {
                return {
                    code: 200,
                    message: 'Not enrolled in this course',
                    data: {
                        is_accessible: false,
                        is_enrolled: false,
                        is_locked: true,
                        lock_reason: 'You are not enrolled in this course',
                    },
                };
            }

            // Get lesson with prerequisite info
            const lesson = await prisma.lesson.findUnique({
                where: { id: lesson_id },
                select: {
                    id: true,
                    title: true,
                    is_sequential: true,
                    prerequisite_lesson_ids: true,
                    require_pass_quiz: true,
                    chapter: {
                        select: {
                            course_id: true,
                        },
                    },
                },
            });

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

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

            // If not sequential, allow access
            if (!lesson.is_sequential) {
                return {
                    code: 200,
                    message: 'Lesson is accessible',
                    data: {
                        is_accessible: true,
                        is_enrolled: true,
                        is_locked: false,
                    },
                };
            }

            const prerequisiteIds = lesson.prerequisite_lesson_ids as number[] | null;

            // If no prerequisites, allow access
            if (!prerequisiteIds || prerequisiteIds.length === 0) {
                return {
                    code: 200,
                    message: 'Lesson is accessible',
                    data: {
                        is_accessible: true,
                        is_enrolled: true,
                        is_locked: false,
                    },
                };
            }

            // Get prerequisite lessons info
            const prerequisiteLessons = await prisma.lesson.findMany({
                where: {
                    id: { in: prerequisiteIds },
                },
                select: {
                    id: true,
                    title: true,
                    require_pass_quiz: true,
                    quiz: {
                        select: {
                            id: true,
                            title: true,
                        },
                    },
                },
            });

            // Get user's progress for prerequisite lessons
            const prerequisiteProgress = await prisma.lessonProgress.findMany({
                where: {
                    user_id: decoded.id,
                    lesson_id: { in: prerequisiteIds },
                },
            });

            const progressMap = new Map(prerequisiteProgress.map(p => [p.lesson_id, p]));

            // Check if all prerequisites are completed
            const requiredLessons: { id: number; title: { th: string; en: string }; is_completed: boolean }[] = [];
            let allCompleted = true;

            for (const prereqLesson of prerequisiteLessons) {
                const progress = progressMap.get(prereqLesson.id);
                const isCompleted = progress?.is_completed ?? false;

                if (!isCompleted) {
                    allCompleted = false;
                }

                requiredLessons.push({
                    id: prereqLesson.id,
                    title: prereqLesson.title as { th: string; en: string },
                    is_completed: isCompleted,
                });
            }

            // Check if any prerequisite requires passing quiz
            let requiredQuizPass: { lesson_id: number; quiz_id: number; title: { th: string; en: string }; is_passed: boolean } | undefined;

            for (const prereqLesson of prerequisiteLessons) {
                if (prereqLesson.require_pass_quiz && prereqLesson.quiz) {
                    // Check if user passed the quiz
                    const quizAttempt = await prisma.quizAttempt.findFirst({
                        where: {
                            user_id: decoded.id,
                            quiz_id: prereqLesson.quiz.id,
                            is_passed: true,
                        },
                    });

                    if (!quizAttempt) {
                        allCompleted = false;
                        requiredQuizPass = {
                            lesson_id: prereqLesson.id,
                            quiz_id: prereqLesson.quiz.id,
                            title: prereqLesson.quiz.title as { th: string; en: string },
                            is_passed: false,
                        };
                        break;
                    }
                }
            }

            if (allCompleted) {
                return {
                    code: 200,
                    message: 'Lesson is accessible',
                    data: {
                        is_accessible: true,
                        is_enrolled: true,
                        is_locked: false,
                    },
                };
            }

            // Not all prerequisites completed
            return {
                code: 200,
                message: 'Lesson is locked',
                data: {
                    is_accessible: false,
                    is_enrolled: true,
                    is_locked: true,
                    lock_reason: 'กรุณาเรียนบทเรียนก่อนหน้าให้ครบก่อน',
                    required_lessons: requiredLessons,
                    required_quiz_pass: requiredQuizPass,
                },
            };
        } catch (error) {
            logger.error(error);
            throw error;
        }
    }

    async getVideoProgress(input: GetVideoProgressInput): Promise<GetVideoProgressResponse> {
        try {
            const { token, lesson_id } = input;
            const decoded = jwt.verify(token, config.jwt.secret) as { id: number; type: string };

            // Get lesson to find course_id
            const lesson = await prisma.lesson.findUnique({
                where: { id: lesson_id },
                select: {
                    id: true,
                    chapter: {
                        select: { course_id: true },
                    },
                },
            });

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

            const course_id = lesson.chapter.course_id;

            // Check enrollment
            const enrollment = await prisma.enrollment.findUnique({
                where: {
                    unique_enrollment: {
                        user_id: decoded.id,
                        course_id,
                    },
                },
            });

            if (!enrollment) {
                throw new ForbiddenError('You are not enrolled in this course');
            }

            // Get progress
            const progress = await prisma.lessonProgress.findUnique({
                where: {
                    user_id_lesson_id: {
                        user_id: decoded.id,
                        lesson_id,
                    },
                },
            });

            // Return null if no progress found
            if (!progress) {
                return {
                    code: 200,
                    message: 'No video progress found',
                    data: null,
                };
            }

            return {
                code: 200,
                message: 'Video progress retrieved successfully',
                data: {
                    lesson_id: progress.lesson_id,
                    video_progress_seconds: progress.video_progress_seconds,
                    video_duration_seconds: progress.video_duration_seconds,
                    video_progress_percentage: progress.video_progress_percentage ? Number(progress.video_progress_percentage) : null,
                    is_completed: progress.is_completed,
                    completed_at: progress.completed_at,
                    last_watched_at: progress.last_watched_at,
                },
            };
        } catch (error) {
            logger.error(error);
            throw error;
        }
    }

    async saveVideoProgress(input: SaveVideoProgressInput): Promise<SaveVideoProgressResponse> {
        try {
            const { token, lesson_id, video_progress_seconds, video_duration_seconds } = input;
            const decoded = jwt.verify(token, config.jwt.secret) as { id: number; type: string };

            // Get lesson to find course_id
            const lesson = await prisma.lesson.findUnique({
                where: { id: lesson_id },
                select: {
                    id: true,
                    chapter: {
                        select: { course_id: true },
                    },
                },
            });

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

            const course_id = lesson.chapter.course_id;

            // Check enrollment
            const enrollment = await prisma.enrollment.findUnique({
                where: {
                    unique_enrollment: {
                        user_id: decoded.id,
                        course_id,
                    },
                },
            });

            if (!enrollment) {
                throw new ForbiddenError('You are not enrolled in this course');
            }

            // Calculate progress percentage (avoid division by zero)
            const progressPercentage = video_duration_seconds && video_duration_seconds > 0
                ? (video_progress_seconds / video_duration_seconds) * 100
                : null;

            // Auto-complete at >= 99% OR when video_progress_seconds >= video_duration_seconds
            const isCompleted = (progressPercentage !== null && progressPercentage >= 99) ||
                !!(video_duration_seconds && video_progress_seconds >= video_duration_seconds);

            // Save video progress (without marking complete yet)
            const progress = await prisma.lessonProgress.upsert({
                where: {
                    user_id_lesson_id: {
                        user_id: decoded.id,
                        lesson_id,
                    },
                },
                create: {
                    user_id: decoded.id,
                    lesson_id,
                    video_progress_seconds,
                    video_duration_seconds: video_duration_seconds ?? null,
                    video_progress_percentage: progressPercentage,
                    is_completed: false,
                    last_watched_at: new Date(),
                },
                update: {
                    video_progress_seconds,
                    video_duration_seconds: video_duration_seconds ?? null,
                    video_progress_percentage: progressPercentage,
                    last_watched_at: new Date(),
                },
            });

            // If video completed, mark lesson as complete and update enrollment progress
            let enrollmentProgress: { progress_percentage: number; is_course_completed: boolean } | undefined;
            if (isCompleted) {
                const result = await this.markLessonComplete(decoded.id, lesson_id, course_id);
                enrollmentProgress = result.enrollmentProgress;
            }

            return {
                code: 200,
                message: 'Video progress saved successfully',
                data: {
                    lesson_id: progress.lesson_id,
                    video_progress_seconds: progress.video_progress_seconds,
                    video_duration_seconds: progress.video_duration_seconds,
                    video_progress_percentage: progress.video_progress_percentage ? Number(progress.video_progress_percentage) : null,
                    is_completed: isCompleted || progress.is_completed,
                    last_watched_at: progress.last_watched_at!,
                    course_progress_percentage: enrollmentProgress?.progress_percentage,
                    is_course_completed: enrollmentProgress?.is_course_completed,
                },
            };
        } catch (error) {
            logger.error(error);
            throw error;
        }
    }

    async completeLesson(input: CompleteLessonInput): Promise<CompleteLessonResponse> {
        try {
            const { token, lesson_id } = input;
            const decoded = jwt.verify(token, config.jwt.secret) as { id: number; type: string };

            // Get lesson with chapter and course info
            const lesson = await prisma.lesson.findUnique({
                where: { id: lesson_id },
                select: {
                    id: true,
                    sort_order: true,
                    chapter: {
                        select: {
                            id: true,
                            course_id: true,
                            sort_order: true,
                            lessons: {
                                where: { is_published: true },
                                orderBy: { sort_order: 'asc' },
                                select: { id: true, sort_order: true },
                            },
                            course: {
                                select: {
                                    have_certificate: true,
                                    chapters: {
                                        where: { is_published: true },
                                        orderBy: { sort_order: 'asc' },
                                        include: {
                                            lessons: {
                                                where: { is_published: true },
                                                orderBy: { sort_order: 'asc' },
                                                select: { id: true },
                                            },
                                        },
                                    },
                                },
                            },
                        },
                    },
                },
            });

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

            const course_id = lesson.chapter.course_id;

            // Check enrollment
            const enrollment = await prisma.enrollment.findUnique({
                where: {
                    unique_enrollment: {
                        user_id: decoded.id,
                        course_id,
                    },
                },
            });

            if (!enrollment) {
                throw new ForbiddenError('You are not enrolled in this course');
            }

            // Mark lesson as complete and update enrollment progress
            const { lessonProgress, enrollmentProgress } = await this.markLessonComplete(decoded.id, lesson_id, course_id);
            const { progress_percentage: course_progress_percentage, is_course_completed } = enrollmentProgress;

            // Find next lesson
            const currentChapterLessons = lesson.chapter.lessons;
            const currentLessonIndex = currentChapterLessons.findIndex(l => l.id === lesson_id);
            let next_lesson_id: number | null = null;

            if (currentLessonIndex < currentChapterLessons.length - 1) {
                // Next lesson in current chapter
                next_lesson_id = currentChapterLessons[currentLessonIndex + 1].id;
            } else {
                // Find next chapter's first lesson
                const allChapters = lesson.chapter.course.chapters;
                const currentChapterIndex = allChapters.findIndex(ch => ch.id === lesson.chapter.id);
                if (currentChapterIndex < allChapters.length - 1) {
                    const nextChapter = allChapters[currentChapterIndex + 1];
                    if (nextChapter.lessons.length > 0) {
                        next_lesson_id = nextChapter.lessons[0].id;
                    }
                }
            }

            // Issue certificate if course completed and has certificate
            let certificate_issued: boolean | undefined;
            if (is_course_completed && lesson.chapter.course.have_certificate) {
                // Check if certificate already exists
                const existingCertificate = await prisma.certificate.findFirst({
                    where: {
                        user_id: decoded.id,
                        course_id,
                    },
                });

                if (!existingCertificate) {
                    await prisma.certificate.create({
                        data: {
                            user_id: decoded.id,
                            course_id,
                            enrollment_id: enrollment.id,
                            file_path: `certificates/${course_id}/${decoded.id}/${Date.now()}.pdf`,
                            issued_at: new Date(),
                        },
                    });
                    certificate_issued = true;
                } else {
                    certificate_issued = false;
                }
            }

            return {
                code: 200,
                message: 'Lesson completed successfully',
                data: {
                    lesson_id: lessonProgress.lesson_id,
                    is_completed: lessonProgress.is_completed,
                    completed_at: lessonProgress.completed_at!,
                    course_progress_percentage,
                    is_course_completed,
                    next_lesson_id,
                    certificate_issued,
                },
            };
        } catch (error) {
            logger.error(error);
            throw error;
        }
    }

    /**
     * ส่งคำตอบ Quiz และคำนวณคะแนน
     * Submit quiz answers and calculate score
     */
    async submitQuiz(input: SubmitQuizInput): Promise<SubmitQuizResponse> {
        try {
            const { token, course_id, lesson_id, answers } = input;
            const decoded = jwt.verify(token, config.jwt.secret) as { id: number };

            // Check enrollment
            const enrollment = await prisma.enrollment.findUnique({
                where: {
                    unique_enrollment: {
                        user_id: decoded.id,
                        course_id,
                    },
                },
            });

            if (!enrollment) {
                throw new ForbiddenError('You are not enrolled in this course');
            }

            // 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,
                                },
                            },
                        },
                    },
                    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');
            }

            const quiz = lesson.quiz;

            // Get previous attempt count
            const previousAttempts = await prisma.quizAttempt.count({
                where: {
                    user_id: decoded.id,
                    quiz_id: quiz.id,
                },
            });
            const attemptNumber = previousAttempts + 1;

            // Calculate score
            let totalScore = 0;
            let earnedScore = 0;
            let correctAnswers = 0;
            const answersReview: {
                question_id: number;
                selected_choice_id: number;
                correct_choice_id: number;
                is_correct: boolean;
                score: number;
            }[] = [];

            for (const question of quiz.questions) {
                totalScore += question.score;

                // Find the correct choice for this question
                const correctChoice = question.choices.find(c => c.is_correct);
                const correctChoiceId = correctChoice?.id ?? 0;

                // Find student's answer for this question
                const studentAnswer = answers.find(a => a.question_id === question.id);
                const selectedChoiceId = studentAnswer?.choice_id ?? 0;

                // Check if answer is correct
                const isCorrect = selectedChoiceId === correctChoiceId;
                if (isCorrect) {
                    earnedScore += question.score;
                    correctAnswers++;
                }

                answersReview.push({
                    question_id: question.id,
                    selected_choice_id: selectedChoiceId,
                    correct_choice_id: correctChoiceId,
                    is_correct: isCorrect,
                    score: isCorrect ? question.score : 0,
                });
            }

            // Calculate percentage and check if passed
            const scorePercentage = totalScore > 0 ? (earnedScore / totalScore) * 100 : 0;
            const isPassed = scorePercentage >= quiz.passing_score;

            // Create quiz attempt record
            const now = new Date();
            const quizAttempt = await prisma.quizAttempt.create({
                data: {
                    user_id: decoded.id,
                    quiz_id: quiz.id,
                    score: earnedScore,
                    total_questions: quiz.questions.length,
                    correct_answers: correctAnswers,
                    is_passed: isPassed,
                    attempt_number: attemptNumber,
                    answers: answers as any, // Store student answers as JSON
                    started_at: now,
                    completed_at: now,
                },
            });

            // If passed, mark lesson as complete and update enrollment progress
            let enrollmentProgress: { progress_percentage: number; is_course_completed: boolean } | undefined;
            if (isPassed) {
                const result = await this.markLessonComplete(decoded.id, lesson_id, course_id);
                enrollmentProgress = result.enrollmentProgress;
            }

            // Build response based on show_answers_after_completion setting
            const showAnswers = quiz.show_answers_after_completion;

            return {
                code: 200,
                message: isPassed ? 'Quiz passed!' : 'Quiz completed',
                data: {
                    attempt_id: quizAttempt.id,
                    quiz_id: quiz.id,
                    score: earnedScore,
                    total_score: totalScore,
                    total_questions: quiz.questions.length,
                    correct_answers: showAnswers ? correctAnswers : undefined,
                    is_passed: isPassed,
                    passing_score: quiz.passing_score,
                    attempt_number: attemptNumber,
                    started_at: quizAttempt.started_at,
                    completed_at: quizAttempt.completed_at!,
                    answers_review: showAnswers ? answersReview : undefined,
                    course_progress_percentage: enrollmentProgress?.progress_percentage,
                    is_course_completed: enrollmentProgress?.is_course_completed,
                },
            };
        } catch (error) {
            logger.error(error);
            throw error;
        }
    }

    /**
     * ดึงคะแนน Quiz ที่เคยทำของนักเรียน
     * Get student's quiz attempts for a lesson
     */
    async getQuizAttempts(input: GetQuizAttemptsInput): Promise<GetQuizAttemptsResponse> {
        try {
            const { token, course_id, lesson_id } = input;
            const decoded = jwt.verify(token, config.jwt.secret) as { id: number };

            // Check enrollment
            const enrollment = await prisma.enrollment.findUnique({
                where: {
                    unique_enrollment: {
                        user_id: decoded.id,
                        course_id,
                    },
                },
            });

            if (!enrollment) {
                throw new ForbiddenError('You are not enrolled in this course');
            }

            // 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');
            }

            // Get all quiz attempts for this user
            const attempts = await prisma.quizAttempt.findMany({
                where: {
                    user_id: decoded.id,
                    quiz_id: lesson.quiz.id,
                },
                orderBy: { attempt_number: 'desc' },
            });

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

            // Format attempts data
            const attemptsData = attempts.map(attempt => ({
                id: attempt.id,
                quiz_id: attempt.quiz_id,
                score: attempt.score,
                total_score: totalScore,
                total_questions: attempt.total_questions,
                correct_answers: attempt.correct_answers,
                is_passed: attempt.is_passed,
                attempt_number: attempt.attempt_number,
                started_at: attempt.started_at,
                completed_at: attempt.completed_at,
            }));

            // Find best score and latest attempt
            const bestScore = attempts.length > 0 
                ? Math.max(...attempts.map(a => a.score)) 
                : null;
            const latestAttempt = attemptsData.length > 0 ? attemptsData[0] : null;

            return {
                code: 200,
                message: 'Quiz attempts 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,
                    attempts: attemptsData,
                    best_score: bestScore,
                    latest_attempt: latestAttempt,
                },
            };
        } catch (error) {
            logger.error(error);
            throw error;
        }
    }
}