from faulthandler import is_enabled
import random
from statistics import mode
import string
import os
import datetime
from django.db import models
from django.db.models.fields import DateField
from django.utils import timezone
from phonenumber_field.modelfields import PhoneNumberField
from django.contrib.auth.models import User
from django.db.models.signals import post_save, post_delete, pre_save
from django.dispatch import receiver
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from django.contrib.auth.validators import UnicodeUsernameValidator
from django.conf import settings
from django_otp.plugins.otp_totp.models import TOTPDevice
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from PIL import Image
import moviepy.editor as mp
from io import BytesIO
from django.core.files.base import ContentFile
from pdf2image import convert_from_path
# from pdf2image import convert_from_path


def get_random_str():
    letters = string.printable[:-38]
    return ''.join(random.choice(letters) for i in range(10))


# def video_upload_path(instance, filename):
#    return 'videos/{}/week_{}/{}/{}'.format(instance.coursecontent.course.title, instance.coursecontent.week, get_random_str(), filename)

# def lecture_note_upload_path(instance, filename):
#    return 'lecture-notes/{}/week_{}/{}/{}'.format(instance.coursecontent.course.title, instance.coursecontent.week, get_random_str(), filename)

# def homework_upload_path(instance, filename):
#    return 'homeworks/{}/week_{}/{}/{}'.format(instance.coursecontent.course.title, instance.coursecontent.week, get_random_str(), filename)

# def homework_submission_upload_path(instance, filename):
#    return 'homework-submissions/{}/{}/week_{}/{}/{}'.format(instance.coursecontent.course.title, instance.student.id, instance.coursecontent.week, get_random_str(), filename)

# def homework_sub_review_upload_path(instance, filename):
#    return 'homework-submissions-review/{}/{}/week_{}/{}/{}'.format(instance.coursecontent.course.title, instance.student.id, instance.coursecontent.week, get_random_str(), filename)

# def exam_feedback_upload_path(instance, filename):
#    return 'exam-feedbacks/{}/{}/{}/{}'.format(instance.course.title, instance.student.id, get_random_str(), filename)

# def course_image_upload_path(instance, filename):
#    return images/course-images/{}/{}'.format(instance.title, filename)


def video_upload_path(instance, filename):
    return '{}/{}/videos/week_{}/{}/{}'.format(instance.coursecontent.course.academic_session.title,
                                               instance.coursecontent.course.title, instance.coursecontent.week,
                                               get_random_str(), filename)


def lecture_note_upload_path(instance, filename):
    return '{}/{}/lecture-notes/week_{}/{}/{}'.format(instance.coursecontent.course.academic_session.title,
                                                      instance.coursecontent.course.title, instance.coursecontent.week,
                                                      get_random_str(), filename)


def homework_upload_path(instance, filename):
    return '{}/{}/homeworks/week_{}/{}/{}'.format(instance.coursecontent.course.academic_session.title,
                                                  instance.coursecontent.course.title, instance.coursecontent.week,
                                                  get_random_str(), filename)


def homework_submission_upload_path(instance, filename):
    return '{}/{}/homework-submissions/{}/week_{}/{}/{}'.format(instance.coursecontent.course.academic_session.title,
                                                                instance.coursecontent.course.title,
                                                                instance.student.id, instance.coursecontent.week,
                                                                get_random_str(), filename)


def homework_sub_review_upload_path(instance, filename):
    return '{}/{}/homework-submissions-review/{}/week_{}/{}/{}'.format(
        instance.coursecontent.course.academic_session.title, instance.coursecontent.course.title, instance.student.id,
        instance.coursecontent.week, get_random_str(), filename)


def exam_feedback_upload_path(instance, filename):
    return '{}/{}/exam-feedbacks/{}/{}/{}'.format(instance.course.academic_session.title, instance.course.title,
                                                  instance.student.id, get_random_str(), filename)


def course_image_upload_path(instance, filename):
    return 'courses/{}/course-image/{}'.format(instance.id, get_random_str()+'_'+filename)


def course_syllabus_upload_path(instance, filename):
    return 'courses/{}/syllabus/{}'.format(instance.id, get_random_str()+'_'+filename)


def user_image_upload_path(instance, filename):
    return 'user-images/user_{}/{}'.format(instance.user.id, filename)


def exam_file_upload_path(instance, filename):
    return '{}/{}/exam-file-submissions/student-exam-{}/{}/{}'.format(
        instance.ans.student_exam.exam.course.academic_session.title,
        instance.ans.student_exam.exam.course.title,
        instance.ans.student_exam.id, get_random_str(), filename)


def discussion_post_file_upload_path(instance, filename):
    return '{}/{}/discussion-post-files/{}/{}'.format(
        instance.discussion_post.usercourse.course.academic_session.title,
        instance.discussion_post.usercourse.course.title,
        instance.discussion_post.id,
        get_random_str()+'_'+filename)


def discussion_reply_file_upload_path(instance, filename):
    return '{}/{}/discussion-reply-files/{}/{}/{}'.format(
        instance.discussion_reply.discussion_post.course.academic_session.title,
        instance.discussion_reply.discussion_post.course.title,
        instance.discussion_reply.discussion_post.id,
        instance.discussion_reply.id,
        get_random_str()+'_'+filename)


def recorded_video_file_upload_path(instance, filename):
    return '{}/{}/recorded-video-files/{}/{}'.format(
        instance.usercourse.course.academic_session.title,
        instance.usercourse.course.title,
        instance.user.id,
        get_random_str()+'_'+filename)

def instructor_documents_upload_path(instance, filename):
    return f"instructors/{instance.instructor.id}/documents/{filename}"

def organization_logos(instance, filename):
    return 'organization/{}/{}'.format(instance.organization.name,get_random_str()+'_'+filename)

def video_content_upload_path(instance, filename):
    return 'courses/{}/contents/{}/{}'.format(instance.usercourse.course.id,
                                        instance.course_content.id, get_random_str()+'content_element'+filename)


def selfpaced_content_upload_path(instance, filename):
    return 'courses/{}/contents/{}/{}'.format(instance.course_content.course.id,
                                    instance.course_content.id, get_random_str()+'content_element'+filename)


def selfpaced_resource_upload_path(instance, filename):
    return 'courses/{}/contents/{}/{}'.format(instance.video.course_content.course.id,
                                    instance.video.course_content.id, get_random_str()+'_resource_'+filename)


def file_content_upload_path(instance, filename):
    return '{}/file_contents/{}'.format(instance.usercourse.course.title,
                                         get_random_str()+'_'+filename)


def assignment_attachment_upload_path(instance, filename):
    return '{}/assignment_attachments/{}'.format(
        instance.assignment.usercourse.course.title,
        get_random_str()+'_'+filename
    )


def assignment_time_extension_attachment_upload_path(instance, filename):
    return '{}/assignment_time_extension_attachments/{}'.format(
        instance.assignment_time_extension.assignment.course.title,
        get_random_str()+'_'+filename
    )


def assignment_submission_attachment_upload_path(instance, filename):
    return '{}/assignment_submission_attachments/{}'.format(
        instance.assignment_submission.assignment.course.title,
        get_random_str()+'_'+filename
    )


def announcement_post_file_upload_path(instance, filename):
    return '{}/{}/announcement-post-files/{}/{}'.format(
        instance.announcement_post.course.academic_session.title,
        instance.announcement_post.course.title,
        instance.announcement_post.id,
        get_random_str()+'_'+filename)


def announcement_reply_file_upload_path(instance, filename):
    return '{}/{}/announcement-reply-files/{}/{}/{}'.format(
        instance.announcement_reply.announcement_post.course.academic_session.title,
        instance.announcement_reply.announcement_post.course.title,
        instance.announcement_reply.announcement_post.id,
        instance.announcement_reply.id,
        get_random_str()+'_'+filename)


################################# Delete Unused files #################################
# Credit: https://cmljnelson.blog/2020/06/22/delete-files-when-deleting-models-in-django/
# Only delete the file if no other instances of that model are using it


def delete_file_if_unused(model, instance, field, instance_file_field):
    dynamic_field = {}
    dynamic_field[field.name] = instance_file_field.name
    other_refs_exist = model.objects.filter(
        **dynamic_field).exclude(pk=instance.pk).exists()
    if not other_refs_exist:
        instance_file_field.delete(False)


# Whenever ANY model is deleted, if it has a file field on it, delete the associated file too


@receiver(post_delete)
def delete_files_when_row_deleted_from_db(sender, instance, **kwargs):
    for field in sender._meta.concrete_fields:
        if isinstance(field, models.FileField):
            instance_file_field = getattr(instance, field.name)
            delete_file_if_unused(sender, instance, field, instance_file_field)

    delete_empty_directories()


# Delete the file if something else get uploaded in its place


@receiver(pre_save)
def delete_files_when_file_changed(sender, instance, **kwargs):
    # Don't run on initial save
    if not instance.pk:
        return
    for field in sender._meta.concrete_fields:
        if isinstance(field, models.FileField):
            # its got a file field. Let's see if it changed
            try:
                instance_in_db = sender.objects.get(pk=instance.pk)
            except sender.DoesNotExist:
                # We are probably in a transaction and the PK is just temporary
                # Don't worry about deleting attachments if they aren't actually saved yet.
                return
            instance_in_db_file_field = getattr(instance_in_db, field.name)
            instance_file_field = getattr(instance, field.name)
            if instance_in_db_file_field.name != instance_file_field.name:
                delete_file_if_unused(
                    sender, instance, field, instance_in_db_file_field)


# Delete empty folders


def delete_empty_directories():
    for root, dirs, files in os.walk(settings.MEDIA_ROOT):
        for d in dirs:
            dir = os.path.join(root, d)
            # check if dir is empty
            if not os.listdir(dir):
                os.rmdir(dir)


######################################################################################
class Organization(models.Model):
    name = models.CharField(max_length=200, unique=True)
    description = models.TextField(null=True, blank=True)
    email = models.EmailField(unique=True, null=True, blank=True)
    phone = models.CharField(max_length=15, null=True, blank=True)
    address = models.TextField(null=True, blank=True)
    website = models.URLField(null=True, blank=True)
    logo = models.ImageField(upload_to='organization_logos', null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    is_active = models.BooleanField(default=True)

    def __str__(self):
        return self.name


class UserInformation(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, default=None, related_name="userinformation")

    role = models.CharField(
        max_length=32,
        choices=(
            ('Admin', 'Admin'),
            ('OrgAdmin', 'OrgAdmin'),
            ('Instructor', 'Instructor'),
            ('Guardian', 'Guardian'),
            ('Student', 'Student')
        ),
        default='Student'
    )

    phone_number = PhoneNumberField(null=True, blank=True)
    image = models.ImageField(upload_to=user_image_upload_path, null=True, blank=True)
    location = models.CharField(max_length=32, null=True, blank=True)

    gender = models.CharField(
        max_length=32,
        choices=(
            ('Male', 'Male'),
            ('Female', 'Female'),
            ('Others', 'Others')
        ),
        default='Male',
        null=True,
        blank=True
    )

    dob = models.DateField(null=True, blank=True)
    parents_name = models.CharField(max_length=100, null=True, blank=True)
    pin_code = models.CharField(max_length=10, null=True, blank=True)
    time_zone = models.CharField(max_length=64, null=True, blank=True)
    is_organization = models.BooleanField(default=False)
    organization = models.OneToOneField(Organization, on_delete=models.CASCADE, default=None, null=True, blank=True, related_name="orguser")
    referal_code = models.CharField(max_length=50, null=True, blank=True)
    profile_lock = models.CharField(
        max_length=32,
        choices=(
            ('incomplete', 'Incomplete'),
            ('waiting_approval', 'Waiting for Approval'),
            ('completed', 'Completed')
        ),
        default='completed',
        null=True,
        blank=True
    )

    # List of specific fields to include in the profile completion calculation
    fields_to_check = [
        'role', 'phone_number', 'location', 'gender', 'dob', 'pin_code', 'time_zone'
    ]

    def calculate_user_profile_completion(self):
        total_required_fields = 0  # Counter for the fields to check
        filled_required_fields = 0  # Counter for the fields that are filled

        # Loop through the specified fields in fields_to_check
        for field_name in self.fields_to_check:
            field = self._meta.get_field(field_name)

            # Check if the field has a value (not None or empty)
            value = getattr(self, field_name)
            if value not in [None, ""]:  # Ignore None or empty values
                filled_required_fields += 1
            total_required_fields += 1

        # Calculate the percentage of completion
        if total_required_fields == 0:  # To avoid division by zero if no fields are checked
            return 100
        completion_percentage = (filled_required_fields / total_required_fields) * 100
        return round(completion_percentage, 0)
    

    def __str__(self):
        return f'{self.user.first_name} {self.user.last_name}'

    def name(self):
        return f'{self.user.first_name} {self.user.last_name}'

    @property
    def full_name(self):
        return f'{self.user.first_name} {self.user.last_name}'


@receiver(post_save, sender=User)
def create_user_information(sender, instance, created, **kwargs):
    if created:
        UserInformation.objects.create(user=instance)


@receiver(post_save, sender=User)
def save_user_information(sender, instance, **kwargs):
    instance.userinformation.save()


class UserApproval(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, default=None)
    status_choices = (('Not Approved', 'Not Approved'),
                      ('Approved', 'Approved'),
                      ('On Hold', 'On Hold'),
                      ('Rejected', 'Rejected'))
    # Not Approved, Approved, Rejected, On Hold
    approval_status = models.CharField(
        max_length=128, choices=status_choices, default='Not Approved')
    created_at = models.DateTimeField(auto_now_add=True, null=True)

    def __str__(self):
        return f'{self.user.first_name} {self.user.last_name} | {self.approval_status}'


@receiver(post_save, sender=User)
def create_user_approval(sender, instance, created, **kwargs):
    if created:
        UserApproval.objects.create(user=instance)


@receiver(post_save, sender=User)
def save_user_approval(sender, instance, **kwargs):
    instance.userapproval.save()


class UserLoginSession(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, default=None)
    device = models.CharField(max_length=128, null=True, blank=True)
    address = models.CharField(max_length=256, null=True, blank=True)
    login_time = models.DateTimeField(default=timezone.now)
    logout_time = models.DateTimeField(blank=True, null=True)
    is_logged_in = models.BooleanField(default=False)
    # token_lifespan = models.IntegerField(default=0)
    # location = models.CharField(max_length=254, null=True, blank=True)


class AcademicSession(models.Model):
    title = models.CharField(max_length=256, unique=True)
    details = models.CharField(max_length=2000, blank=True, null=True)
    time_created = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ['-time_created']


class Course(models.Model):
    title = models.CharField(max_length=256)
    details = models.TextField(blank=True, null=True)
    duration = models.IntegerField()
    rating = models.DecimalField(
        max_digits=2, decimal_places=1, blank=True, null=True)
    is_active = models.BooleanField(default=False)
    is_archived = models.BooleanField(default=False)
    image = models.ImageField(
        upload_to=course_image_upload_path, blank=True, null=True)    
    instructor = models.ManyToManyField(
        'Instructor', related_name='course')
    student = models.ManyToManyField(
        User, related_name='course')
    # academic_session = models.ForeignKey(
    #     'AcademicSession', related_name='course', on_delete=models.SET_NULL, null=True, blank=True)

    # new addition 3-11-2024
    course_week = models.TextField(null=True)
    number_class = models.IntegerField(default=0)
    student_limit = models.IntegerField(default=0)
    country_fees = models.JSONField(null=True, blank=True)
    # course_cont_highlight = models.JSONField(null=True, blank=True)
    # course_level = models.JSONField(null=True, blank=True)
    # course_prerequisites = models.JSONField(null=True, blank=True)
    # course_why_choose = models.JSONField(null=True, blank=True)

    # new addition 10-12-2024
    start_date = models.DateField(null=True, blank=True)
    end_date = models.DateField(null=True, blank=True)
    group_discount = models.JSONField(null=True, blank=True)
    # course_days = models.JSONField(null=True, blank=True)

    # new addition 26-12-2024
    # short_details = models.TextField(blank=True, null=True)

    #new addition 25-01-2025
    # age_group = models.CharField(max_length=128, null=True, blank=True)

    # new addition 23-02-2025
    syllabus = models.FileField(
        upload_to=course_syllabus_upload_path, blank=True, null=True)
    

    # new addition 05-03-2025
    grade_level = models.ForeignKey('GradeLevel', on_delete=models.SET_NULL, related_name='courses', null=True, blank=True)
    education_type = models.ForeignKey('EducationType', on_delete=models.SET_NULL, related_name='courses', null=True, blank=True)
    grade_class = models.ForeignKey('GradeClass', on_delete=models.SET_NULL, related_name='courses', null=True, blank=True)
    subject = models.ManyToManyField('Subject', related_name='courses', blank=True)

    # new addition 06-03-2025
    is_one_to_one = models.BooleanField(default=False)
    is_one_to_group = models.BooleanField(default=False)
    is_one_to_many = models.BooleanField(default=False)
    is_selfpaced = models.BooleanField(default=False)

    # new addition 20-03-2025
    is_organization = models.BooleanField(default=False)
    organization = models.ForeignKey(Organization, on_delete=models.CASCADE, default=None, null=True, blank=True, related_name="orgcourse")

    # new addition 25-03-2025
    study_method = models.CharField(max_length=100, blank=True, null=True)
    assessments = models.CharField(max_length=100, blank=True, null=True)
    entry_requirements = models.CharField(max_length=100, blank=True, null=True)
    language = models.CharField(max_length=100, blank=True, null=True)  #JSON
    what_you_will_learn = models.TextField(blank=True, null=True)
    topics_covered = models.TextField(blank=True, null=True)
    description = models.TextField(blank=True, null=True)
    assessment_details = models.TextField(blank=True, null=True)
    textbooks = models.TextField(blank=True, null=True)
    regarding_requirements = models.TextField(blank=True, null=True)
    about_study_loans = models.TextField(blank=True, null=True)
    why_focus_on_one_subject = models.TextField(blank=True, null=True)
    what_to_learn_next = models.TextField(blank=True, null=True)
    faq = models.JSONField(blank=True, null=True)

    created_at = models.DateTimeField(auto_now_add=True, blank=True, null=True)
    edited_at = models.DateTimeField(auto_now=True, blank=True, null=True)

    # new addition 27-03-2025, modified 7-04-2025
    status_choices = (
        ('Draft', 'Draft'),
        ('Pending', 'Pending'),
        ('Approved', 'Approved')
    )
    course_status = models.CharField(max_length=128, choices=status_choices, default='Pending')

    created_by = models.ForeignKey(User, on_delete=models.SET_NULL, related_name='courses_created', null=True, blank=True)

    def __str__(self):
        return self.title

    def student_count(self):
        return self.student.all().count()

    class Meta:
        ordering = ['created_at']


class CourseContent(models.Model):
    sequence = models.IntegerField(null=True, blank=True)
    course = models.ForeignKey('Course', related_name='course_content', on_delete=models.CASCADE, null=True, blank=True)
    # type_choices = (('Text', 'Text'),
    #                 ('Video', 'Video'),
    #                 ('Attachment', 'Attachment'))
    # content_type = models.CharField(max_length=32, choices=type_choices, blank=True, null=True)
    title = models.CharField(max_length=350, blank=True, null=True)
    is_active = models.BooleanField(default=False, blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True, blank=True, null=True)
    edited_at = models.DateTimeField(auto_now=True, blank=True, null=True)
    created_by = models.ForeignKey(User, on_delete=models.SET_NULL, related_name='course_contents', null=True, blank=True)
    # week = models.IntegerField()
    # homework_deadline = models.DateTimeField(blank=True, null=True)


class Video(models.Model):
    sequence = models.IntegerField(null=True, blank=True)
    course_content = models.ForeignKey('CourseContent', related_name='video', on_delete=models.CASCADE, null=True, blank=True)
    title = models.CharField(max_length=256, blank=True, null=True)
    file = models.FileField(upload_to=selfpaced_content_upload_path, max_length=500, blank=True, null=True)
    # duration = models.IntegerField(blank=True, null=True)  # in seconds
    created_at = models.DateTimeField(auto_now_add=True, blank=True, null=True)
    edited_at = models.DateTimeField(auto_now=True, blank=True, null=True)
    created_by = models.ForeignKey(User, on_delete=models.SET_NULL, related_name='course_content_video', null=True, blank=True)   


class VideoPause(models.Model):
    user = models.ForeignKey(
        User,
        related_name='video_pause',
        on_delete=models.CASCADE
    )
    coursecontent = models.ForeignKey(
        'CourseContent', related_name='video_pause', on_delete=models.CASCADE, null=True, blank=True)
    video = models.ForeignKey('Video', related_name='video_pause', on_delete=models.CASCADE, null=True, blank=True)
    duration = models.FloatField(blank=True, null=True)  # in seconds


class CourseContentDocument(models.Model):
    sequence = models.IntegerField(null=True, blank=True)
    course_content = models.ForeignKey('CourseContent', related_name='document', on_delete=models.CASCADE, null=True, blank=True)
    title = models.CharField(max_length=256, blank=True, null=True)
    file = models.FileField(upload_to=selfpaced_content_upload_path, max_length=500, blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True, blank=True, null=True)
    edited_at = models.DateTimeField(auto_now=True, blank=True, null=True)
    created_by = models.ForeignKey(User, on_delete=models.SET_NULL, related_name='course_content_document', null=True, blank=True)   


class CourseContentResource(models.Model):
    sequence = models.IntegerField(null=True, blank=True)
    title = models.CharField(max_length=256, blank=True, null=True)
    video = models.ForeignKey('Video', related_name='resource', on_delete=models.CASCADE, blank=True, null=True)
    file = models.FileField(upload_to=selfpaced_resource_upload_path, max_length=500, blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True, blank=True, null=True)
    edited_at = models.DateTimeField(auto_now=True, blank=True, null=True)
    created_by = models.ForeignKey(User, on_delete=models.SET_NULL, related_name='course_content_resource', null=True, blank=True)


class CourseContentProgress(models.Model):
    user = models.ForeignKey(
        User,
        related_name='course_content_progress',
        on_delete=models.CASCADE
    )
    coursecontent = models.ForeignKey(
        'CourseContent', related_name='course_content_progress', on_delete=models.CASCADE, null=True, blank=True)
    is_completed = models.BooleanField(default=False)
    video = models.OneToOneField('Video', related_name='course_content_progress', on_delete=models.CASCADE, null=True, blank=True)


class GradeLevel(models.Model):
    title = models.CharField(max_length=50, blank=True, null=True)
    description = models.CharField(max_length=1000, blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    edited_at = models.DateTimeField(auto_now=True)


class EducationType(models.Model):
    title = models.CharField(max_length=50, blank=True, null=True)
    description = models.CharField(max_length=1000, blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    edited_at = models.DateTimeField(auto_now=True)


class GradeClass(models.Model):
    title = models.CharField(max_length=50, blank=True, null=True)
    description = models.CharField(max_length=1000, blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    edited_at = models.DateTimeField(auto_now=True)


class SubjectGroup(models.Model):
    title = models.CharField(max_length=50, blank=True, null=True)
    description = models.CharField(max_length=1000, blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    edited_at = models.DateTimeField(auto_now=True)


class Subject(models.Model):
    subject_group = models.ForeignKey(SubjectGroup, on_delete=models.CASCADE, related_name='subjects', blank=True, null=True)
    title = models.CharField(max_length=50, blank=True, null=True)
    description = models.CharField(max_length=1000, blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    edited_at = models.DateTimeField(auto_now=True)


class CourseMember(models.Model):
    user = models.ForeignKey(User, related_name='course_memberships', on_delete=models.CASCADE)
    invite_to = models.EmailField(blank=True, null=True)
    is_accept = models.BooleanField(default=False)
    course = models.ForeignKey('Course', related_name='course_members', on_delete=models.CASCADE)
    usercourse = models.ForeignKey('UserCourse', related_name='user_course_memberships', on_delete=models.CASCADE)

    def __str__(self):
        return f"{self.user} - {self.course} ({'Accepted' if self.is_accept else 'Pending'})"


class CoursePayment(models.Model):
    course = models.ForeignKey('Course', related_name='course_payment', on_delete=models.CASCADE)
    user = models.ManyToManyField(User, related_name='course_payment')
    total_amount = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    discounted_amount = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    pay_amount = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    no_of_subscriptions = models.IntegerField()
    payment_type = models.CharField(null=True, blank=True)
    tnx_id = models.CharField(null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)

    # new addition 09-03-2025
    duration = models.IntegerField(blank=True, null=True)
    organization = models.ForeignKey('Organization', related_name='payment', on_delete=models.SET_NULL, blank=True, null=True)
    course_type = models.CharField(max_length=50, blank=True, null=True)
    
    def __str__(self):
        return f"Payment by {self.user} for {self.course} - {self.pay_amount}"


class CourseActivity(models.Model):
    course = models.ForeignKey('Course', related_name='course_activities', on_delete=models.CASCADE)
    user = models.ForeignKey(User, related_name='course_activities', on_delete=models.CASCADE)
    last_content_view = models.DateTimeField(null=True)
    content_view_count = models.IntegerField(default=0)
    last_participation = models.DateTimeField(null=True)
    participation_count = models.IntegerField(default=0)

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=['course', 'user'],
                name='unique course_activity'
            )
        ]


class CourseModule(models.Model):
    usercourse = models.ForeignKey(
        'UserCourse', related_name='course_module', on_delete=models.CASCADE, null= True)
    title = models.CharField(max_length=256)
    is_active = models.BooleanField(default=False)
    time_created = models.DateTimeField(auto_now_add=True)
    time_edited = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ['id']


class ModuleContent(models.Model):
    course_module = models.ForeignKey('CourseModule', related_name='module_contents', on_delete=models.CASCADE, null=True)
    type_choices = (('Element', 'Element'),
                    ('Video', 'Video'),
                    ('Attachment', 'Attachment'))
    type = models.CharField(max_length=32, choices=type_choices)
    is_active = models.BooleanField(default=False)
    time_created = models.DateTimeField(auto_now_add=True)
    time_edited = models.DateTimeField(auto_now=True)
    element_content = models.OneToOneField('ElementContent', related_name='module_content', on_delete=models.CASCADE, null=True)
    video_content = models.OneToOneField('VideoContent', related_name='module_content', on_delete=models.CASCADE, null=True)
    attachment_content = models.OneToOneField('AttachmentContent', related_name='module_content', on_delete=models.CASCADE, null=True)

    class Meta:
        ordering = ['id']


class ModuleContentView(models.Model):
    module_content = models.ForeignKey('ModuleContent', related_name='module_content_views', on_delete=models.CASCADE)
    user = models.ForeignKey(User, related_name='module_content_views', on_delete=models.CASCADE)
    time_created = models.DateTimeField(auto_now_add=True)
    time_edited = models.DateTimeField(auto_now=True)

    class Meta:
        unique_together = [['module_content', 'user']]


class ElementContent(models.Model):
    usercourse = models.ForeignKey(
        'UserCourse', related_name='element_contents', on_delete=models.CASCADE, null= True)
    title = models.CharField(max_length=256)
    content = models.TextField()
    time_created = models.DateTimeField(auto_now_add=True)
    time_edited = models.DateTimeField(auto_now=True)


class VideoContent(models.Model):
    usercourse = models.ForeignKey(
        'UserCourse', related_name='video_contents', on_delete=models.CASCADE, null= True)
    title = models.CharField(max_length=256)
    file = models.FileField(upload_to=video_content_upload_path,
                            max_length=256)
    time_created = models.DateTimeField(auto_now_add=True)
    time_edited = models.DateTimeField(auto_now=True)


class AttachmentContent(models.Model):
    usercourse = models.ForeignKey(
        'UserCourse', related_name='attachment_contents', on_delete=models.CASCADE, null= True)
    title = models.CharField(max_length=256)
    file = models.FileField(upload_to=file_content_upload_path,
                            max_length=256)
    time_created = models.DateTimeField(auto_now_add=True)
    time_edited = models.DateTimeField(auto_now=True)


class ContentNote(models.Model):
    user = models.ForeignKey(User, related_name='content_notes', on_delete=models.CASCADE)
    module_content = models.ForeignKey('ModuleContent', related_name='content_notes', on_delete=models.CASCADE)
    text = models.TextField()

    time_created = models.DateTimeField(auto_now_add=True)
    time_edited = models.DateTimeField(auto_now=True)


class Assignment(models.Model):
    usercourse = models.ForeignKey(
        'UserCourse', related_name='assignments', on_delete=models.CASCADE, null= True)
    title = models.CharField(max_length=256)
    content = models.TextField(null=True)
    marks = models.DecimalField(max_digits=4, decimal_places=1, null=True)
    submission_deadline = models.DateTimeField()
    allow_attachment_submission = models.BooleanField(default=False)
    is_active = models.BooleanField(default=False)

    time_created = models.DateTimeField(auto_now_add=True)
    time_edited = models.DateTimeField(auto_now=True)


class AssignmentAttachment(models.Model):
    assignment = models.ForeignKey('Assignment', related_name='assignment_attachments', on_delete=models.CASCADE)
    file = models.FileField(upload_to=assignment_attachment_upload_path,
                            max_length=256)
    time_created = models.DateTimeField(auto_now_add=True)
    time_edited = models.DateTimeField(auto_now=True)


class AssignmentTimeExtension(models.Model):
    assignment = models.ForeignKey(
        'Assignment',
        related_name='assignment_time_extensions',
        on_delete=models.CASCADE
    )
    user = models.ForeignKey(
        User,
        related_name='assignment_time_extensions',
        on_delete=models.CASCADE
    )
    requested_deadline = models.DateTimeField()
    reason = models.TextField(null=True)
    modified_requested_deadline = models.DateTimeField(null=True)
    is_approved = models.BooleanField(null=True)

    class Meta:
        unique_together = [['assignment', 'user']]


class AssignmentTimeExtensionAttachment(models.Model):
        assignment_time_extension = models.ForeignKey(
            'AssignmentTimeExtension',
            related_name='assignment_time_extension_attachments',
            on_delete=models.CASCADE
        )
        file = models.FileField(upload_to=assignment_time_extension_attachment_upload_path,
                                max_length=256)

        time_created = models.DateTimeField(auto_now_add=True)
        time_edited = models.DateTimeField(auto_now=True)


class AssignmentSubmission(models.Model):
    assignment = models.ForeignKey('Assignment', related_name='assignment_submissions', on_delete=models.CASCADE)
    user = models.ForeignKey(
        User,
        related_name='assignment_submissions',
        on_delete=models.CASCADE
    )
    content = models.TextField()
    marks_obtained = models.DecimalField(max_digits=4, decimal_places=1, null=True)
    grader_comment = models.TextField(null=True)

    time_created = models.DateTimeField(auto_now_add=True)
    time_edited = models.DateTimeField(auto_now=True)


class AssignmentSubmissionAttachment(models.Model):
    assignment_submission = models.ForeignKey(
        'AssignmentSubmission',
        related_name='assignment_submission_attachments',
        on_delete=models.CASCADE
    )
    file = models.FileField(upload_to=assignment_submission_attachment_upload_path,
                            max_length=256)

    time_created = models.DateTimeField(auto_now_add=True)
    time_edited = models.DateTimeField(auto_now=True)


# class CourseArchive(models.Model):
#     course = models.OneToOneField(
#         "Course", related_name="course_archive", on_delete=models.CASCADE, null=True, blank=True)
#     is_archived = models.BooleanField(default=False)
#     fileloc = models.CharField(max_length=256, null=True, blank=True)


class LectureNote(models.Model):
    coursecontent = models.ForeignKey(
        'CourseContent', related_name='lecturenote', on_delete=models.CASCADE, null=True, blank=True)
    title = models.CharField(max_length=256, blank=True, null=True)
    file = models.FileField(
        upload_to=lecture_note_upload_path, max_length=256, blank=True, null=True)


class Homework(models.Model):
    coursecontent = models.ForeignKey(
        'CourseContent', related_name='homework', on_delete=models.CASCADE, null=True, blank=True)
    title = models.CharField(max_length=256, blank=True, null=True)
    file = models.FileField(upload_to=homework_upload_path,
                            max_length=256, blank=True, null=True)
    time_created = models.DateTimeField(auto_now_add=True)


class HomeworkSubmission(models.Model):
    coursecontent = models.ForeignKey(
        'CourseContent', related_name='homework_submission', on_delete=models.CASCADE, null=True, blank=True)
    student = models.ForeignKey(
        User, related_name='homework_submission', on_delete=models.CASCADE, null=True, blank=True)
    title = models.CharField(max_length=256, blank=True, null=True)
    file = models.FileField(
        upload_to=homework_submission_upload_path, max_length=256, blank=True, null=True)
    time_created = models.DateTimeField(auto_now_add=True)


class HomeworkSubNewComment(models.Model):
    homeworksubmission = models.ForeignKey(
        'HomeworkSubmission', related_name='homework_sub_new_comment', on_delete=models.CASCADE, null=True, blank=True)
    user = models.ForeignKey(
        User, related_name='homework_sub_new_comment', on_delete=models.CASCADE, null=True, blank=True)
    is_seen = models.BooleanField(default=True)

    class Meta:
        unique_together = ('homeworksubmission', 'user',)


class HomeworkSubComment(models.Model):
    homeworksubmission = models.ForeignKey(
        'HomeworkSubmission', related_name='homework_sub_comment', on_delete=models.CASCADE, null=True, blank=True)
    text = models.CharField(max_length=2048, blank=True, null=True)
    comment_by = models.ForeignKey(
        User, related_name='homework_sub_comment', on_delete=models.CASCADE, null=True, blank=True)
    time = models.DateTimeField(auto_now_add=True)


class HomeworkSubReview(models.Model):
    coursecontent = models.ForeignKey(
        'CourseContent', related_name='homework_sub_review', on_delete=models.CASCADE, null=True, blank=True)
    student = models.ForeignKey(
        User, related_name='homework_sub_review', on_delete=models.CASCADE, null=True, blank=True)
    title = models.CharField(max_length=256, blank=True, null=True)
    file = models.FileField(
        upload_to=homework_sub_review_upload_path, max_length=256, blank=True, null=True)
    time_created = models.DateTimeField(auto_now_add=True)


class ExamFeedback(models.Model):
    course = models.ForeignKey(
        'Course', related_name='exam_feedback', on_delete=models.CASCADE, null=True, blank=True)
    student = models.ForeignKey(
        User, related_name='exam_feedback', on_delete=models.CASCADE, null=True, blank=True)
    title = models.CharField(max_length=256, blank=True, null=True)
    file = models.FileField(
        upload_to=exam_feedback_upload_path, max_length=256, blank=True, null=True)
    time_created = models.DateTimeField(auto_now_add=True)


class Exam(models.Model):
    """Saves data when exam is created.

    Keyword Arguments:
    start_time -- Primary exam start time (datetime)
    duration -- Primary exam duration (minute)
    is_enabled_all -- For disabling primary start time (boolean)

    """
    course = models.ForeignKey('Course', related_name='exam', on_delete=models.CASCADE, null=True, blank=True)
    title = models.CharField(max_length=256)
    instruction = models.CharField(max_length=4000)
    start_time = models.DateTimeField(blank=True, null=True)
    end_time = models.DateTimeField(blank=True, null=True)
    duration = models.IntegerField()
    total_marks = models.DecimalField(max_digits=4, decimal_places=1, null=True)
    status_choices = (('Unpublished', 'Unpublished'),
                      ('Published', 'Published'),
                      ('Finished', 'Finished'))
    status = models.CharField(max_length=64, choices=status_choices, default='Unpublished')
    added_by = models.ForeignKey(User, related_name='exam', on_delete=models.SET_NULL, null=True, blank=True)
    added_on = models.DateTimeField(auto_now_add=True)
    modified_on = models.DateTimeField(auto_now=True)
    is_enabled_all = models.BooleanField(default=False)
    back_tracking = models.BooleanField(default=False)

    def save(self, *args, **kwargs):
        self.end_time = self.start_time + datetime.timedelta(minutes=self.duration)
        super(Exam, self).save(*args, **kwargs)


class ExamSchedule(models.Model):
    """Saves data when students are scheduled to attend exam on customized date & time.

    Keyword Arguments:
    start_time -- Rescheduled exam start time (datetime)
    duration -- Rescheduled exam duration (minute)

    """
    exam = models.ForeignKey('Exam', related_name='exam_schedule', on_delete=models.CASCADE, null=True, blank=True)
    user = models.ForeignKey(User, related_name='exam_schedule', on_delete=models.CASCADE, null=True, blank=True)
    start_time = models.DateTimeField(null=True, blank=True)
    end_time = models.DateTimeField(blank=True, null=True)
    duration = models.IntegerField()
    is_enabled = models.BooleanField(default=False)

    def save(self, *args, **kwargs):
        self.end_time = self.start_time + datetime.timedelta(minutes=self.duration)
        super(ExamSchedule, self).save(*args, **kwargs)

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=['exam', 'user'],
                name='unique exam_schedule'
            )
        ]


class Question(models.Model):
    exam = models.ForeignKey('Exam', related_name='question', on_delete=models.CASCADE, null=True, blank=True)
    question_types = (('MCQ', 'MCQ'),
                      ('Descriptive', 'Descriptive'))
    type = models.CharField(max_length=16, choices=question_types, blank=True, null=True)
    mcq = models.OneToOneField('MCQ', related_name='question', on_delete=models.CASCADE, null=True, blank=True)
    descriptive_q = models.OneToOneField('DescriptiveQ', related_name='question', on_delete=models.CASCADE, null=True,
                                         blank=True)


class MCQ(models.Model):
    exam = models.ForeignKey('Exam', related_name='mcq', on_delete=models.CASCADE, null=True, blank=True)
    q_text = models.CharField(max_length=512)
    marks = models.DecimalField(max_digits=3, decimal_places=1)
    added_on = models.DateTimeField(auto_now_add=True)
    modified_on = models.DateTimeField(auto_now=True)


class Choice(models.Model):
    mcq = models.ForeignKey('MCQ', related_name='choice', on_delete=models.CASCADE, null=True, blank=True)
    text = models.CharField(max_length=128)
    correct = models.BooleanField(default=False)


class DescriptiveQ(models.Model):
    exam = models.ForeignKey('Exam', related_name='descriptive_q', on_delete=models.CASCADE, null=True, blank=True)
    q_text = models.CharField(max_length=10000)
    marks = models.DecimalField(max_digits=3, decimal_places=1)
    note = models.CharField(max_length=1024, blank=True, null=True)
    added_on = models.DateTimeField(auto_now_add=True)
    modified_on = models.DateTimeField(auto_now=True)


class StudentExam(models.Model):
    exam = models.ForeignKey('Exam', related_name='student_exam', on_delete=models.CASCADE, null=True, blank=True)
    user = models.ForeignKey(User, related_name='student_exam', on_delete=models.CASCADE, null=True, blank=True)
    is_finished = models.BooleanField(default=False)
    started_at = models.DateTimeField(auto_now_add=True)
    finished_at = models.DateTimeField(null=True, blank=True)
    total_marks_obtained = models.DecimalField(max_digits=4, decimal_places=1, null=True)
    is_graded = models.BooleanField(default=False)
    modified_on = models.DateTimeField(auto_now=True)
    additonal_duration = models.IntegerField(null=True, blank=True)  # In minutes

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=['exam', 'user'],
                name='unique student_exam'
            )
        ]


class MCQAns(models.Model):
    student_exam = models.ForeignKey('StudentExam', related_name='mcq_ans', on_delete=models.CASCADE, null=True,
                                     blank=True)
    mcq = models.ForeignKey('MCQ', related_name='mcq_ans', on_delete=models.CASCADE, null=True, blank=True)
    choice = models.ManyToManyField('Choice', related_name='mcq_ans')
    marks_obtained = models.DecimalField(max_digits=3, decimal_places=1, null=True)
    added_on = models.DateTimeField(auto_now_add=True)
    modified_on = models.DateTimeField(auto_now=True)

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=['student_exam', 'mcq'],
                name='unique mcq_ans'
            )
        ]


class DescriptiveQAns(models.Model):
    student_exam = models.ForeignKey('StudentExam', related_name='descriptive_q_ans', on_delete=models.CASCADE,
                                     null=True, blank=True)
    descriptive_q = models.ForeignKey('DescriptiveQ', related_name='descriptive_q_ans', on_delete=models.CASCADE,
                                      null=True, blank=True)
    ans = models.CharField(max_length=10000, null=True, blank=True)
    marks_obtained = models.DecimalField(max_digits=3, decimal_places=1, null=True)
    feedback = models.CharField(max_length=5000, null=True, blank=True)
    added_on = models.DateTimeField(auto_now_add=True)
    modified_on = models.DateTimeField(auto_now=True)

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=['student_exam', 'descriptive_q'],
                name='unique descriptive_q_ans'
            )
        ]


def question_picture_upload_path(instance, filename):
    return f'{instance.question.exam.course.academic_session.title}/{instance.question.exam.course.title}/question-file/{instance.question.id}/{get_random_str()}-{filename}'

class PictureForQuestion(models.Model):
    file = models.FileField(upload_to=question_picture_upload_path, max_length=256)
    question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name='question_picture')
    name = models.CharField(max_length=32)

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=['name', 'question'],
                name='unique question_picture_type'
            ),
        ]


class QAMediaFile(models.Model):
    file = models.FileField(upload_to=exam_file_upload_path, max_length=256)
    name = models.CharField(max_length=32)
    file_type = models.CharField(max_length=5)
    ans = models.ForeignKey(DescriptiveQAns, on_delete=models.CASCADE, related_name='files')

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=['name', 'ans'],
                # condition=models.Q(file_type="doc"),
                name='unique docs_file_type'
            ),
            # models.UniqueConstraint(
            #     fields=['name', 'ans']
            # )
        ]


class Instructor(models.Model):
    user = models.OneToOneField(
        User, on_delete=models.CASCADE, null=True, blank=True, related_name='instructor')
    name = models.CharField(max_length=128)
    occupation = models.CharField(max_length=128, null=True, blank=True)
    details = models.CharField(max_length=5000, blank=True, null=True)
    contact_email = models.EmailField(blank=True, null=True)
    status_choices = (('Pending', 'Pending'),
                      ('Active', 'Active'),
                      ('Not Active', 'Not Active'))
    # Pending, Active, Not Active
    status = models.CharField(
        max_length=128, choices=status_choices, default='Pending')
    created_at = models.DateTimeField(auto_now_add=True, null=True)

    #personal info
    is_one_to_one = models.BooleanField(default=False, blank=True, null=True)   # Checkbox to indicate 1 to 1
    is_one_to_group = models.BooleanField(default=False, blank=True, null=True) # Checkbox to indicate 1 to group
    is_one_to_many = models.BooleanField(default=False, blank=True, null=True)  # Checkbox to indicate 1 to many
    is_selfpaced = models.BooleanField(default=False, blank=True, null=True)
    
    hourly_fee = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    city = models.CharField(max_length=128, null=True, blank=True)
    language = models.CharField(max_length=128, null=True, blank=True)
    wp_number = PhoneNumberField(null=True, blank=True)
    skype_id = models.CharField(max_length=128, null=True, blank=True)
    website = models.CharField(max_length=500, blank=True, null=True)
    linked_in_id = models.CharField(max_length=500, blank=True, null=True)

    #organization = models.OneToOneField(Organization, on_delete=models.CASCADE, default=None, null=True, blank=True, related_name="orginstructor")

    # List of fields to check for profile completion
    fields_to_check = [
        'name', 'occupation', 'details', 'contact_email', 'status', 
        'hourly_fee', 'city', 'language', 'wp_number', 'skype_id', 'website', 'linked_in_id'
    ]

    def calculate_instructor_profile_completion(self):
        total_required_fields = 0  # Counter for the fields to check
        filled_required_fields = 0  # Counter for the fields that are filled

        # Loop through the specified fields in fields_to_check
        for field_name in self.fields_to_check:
            field = self._meta.get_field(field_name)

            # Check if the field has a value (not None or empty)
            value = getattr(self, field_name)
            if value not in [None, ""]:  # Ignore None or empty values
                filled_required_fields += 1
            total_required_fields += 1

        # Check if any of the teaching-related fields have data
        teaching_fields = [self.is_one_to_one, self.is_one_to_group, self.is_one_to_many]
        if any(teaching_fields):  # If any of these fields is True
            filled_required_fields += 1
        total_required_fields += 1

        # Calculate the percentage of completion
        if total_required_fields == 0:  # To avoid division by zero if no fields are checked
            return 100
        completion_percentage = (filled_required_fields / total_required_fields) * 100
        return round(completion_percentage, 0)
    
    def __str__(self):
        return self.name


class InstructorTime(models.Model):
    day = models.CharField(max_length=10, null=True, blank=True)
    time = models.TimeField(null=True, blank=True)
    instructor = models.ForeignKey('Instructor', related_name='instructor_time', on_delete=models.CASCADE, null=True, blank=True)
    booked_status = models.BooleanField(default=False, null=True, blank=True)

    class Meta:
        unique_together = ('day', 'time', 'instructor')

class InstructorEducation(models.Model):
    instructor = models.ForeignKey(
        'Instructor', 
        related_name='instructor_educations', 
        on_delete=models.CASCADE, 
        null=True, 
        blank=True
    )
    degree = models.CharField(max_length=500, blank=True, null=True)
    university_name = models.CharField(max_length=500, blank=True, null=True)
    university_city = models.CharField(max_length=150, blank=True, null=True)
    university_country = models.CharField(max_length=200, blank=True, null=True)
    session_start = models.DateField(blank=True, null=True)
    session_end = models.DateField(blank=True, null=True)
    degree_details = models.CharField(max_length=500, blank=True, null=True)
    is_publish = models.BooleanField(default=False)  # Removed null=True
    created_at = models.DateTimeField(auto_now_add=True, blank=True, null=True)
    edited_at = models.DateTimeField(auto_now=True, blank=True, null=True)
    created_by = models.ForeignKey(User, related_name='instructor_educations_created', on_delete=models.SET_NULL, null=True, blank=True)

    class Meta:
        unique_together = ('instructor', 'degree', 'university_name')

    def clean(self):
        from django.core.exceptions import ValidationError
        if self.session_start and self.session_end and self.session_start > self.session_end:
            raise ValidationError("Session end date must be after the start date.")

class InstructorDocuments(models.Model):
    title = models.CharField(max_length=128)
    instructor = models.ForeignKey(
        'Instructor',
        related_name='documents',
        on_delete=models.CASCADE,
        null=True,
        blank=True
    )
    source_type = models.CharField(
        max_length=100, default='image'
    )
    file = models.FileField(upload_to=instructor_documents_upload_path)
    thumbnail = models.ImageField(upload_to='thumbnails/', blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True, blank=True, null=True)
    edited_at = models.DateTimeField(auto_now=True, blank=True, null=True)
    created_by = models.ForeignKey(User, related_name='instructor_documents_created', on_delete=models.SET_NULL, null=True, blank=True)

    def __str__(self):
        return f"{self.title} ({self.source_type})"

    def _generate_image_thumbnail(self):
        try:
            img = Image.open(self.file)

            # Convert RGBA to RGB to avoid "cannot write mode RGBA as JPEG"
            if img.mode in ('RGBA', 'P'):
                img = img.convert('RGB')

            img.thumbnail((300, 300))

            thumb_io = BytesIO()
            img.save(thumb_io, format='JPEG')

            filename = f"thumb_{os.path.basename(self.file.name)}"
            self.thumbnail.save(filename, ContentFile(thumb_io.getvalue()), save=False)
        except Exception as e:
            print(f"Image thumbnail generation failed: {e}")


    def _generate_document_thumbnail(self):
        try:
            pages = convert_from_path(self.file.path, first_page=1, last_page=1)
            if pages:
                thumb_io = BytesIO()
                pages[0].thumbnail((300, 300))
                pages[0].save(thumb_io, format='JPEG')

                filename = f"thumb_{os.path.splitext(os.path.basename(self.file.name))[0]}.jpg"
                self.thumbnail.save(filename, ContentFile(thumb_io.getvalue()), save=False)
        except Exception as e:
            print(f"Document thumbnail generation failed: {e}")

    def _generate_video_thumbnail(self):
        try:
            clip = mp.VideoFileClip(self.file.path)
            frame = clip.get_frame(1.0)  # Frame at 1 second
            img = Image.fromarray(frame)
            img.thumbnail((300, 300))

            thumb_io = BytesIO()
            img.save(thumb_io, format='JPEG')

            filename = f"thumb_{os.path.splitext(os.path.basename(self.file.name))[0]}.jpg"
            self.thumbnail.save(filename, ContentFile(thumb_io.getvalue()), save=False)
            clip.close()
        except Exception as e:
            print(f"Video thumbnail generation failed: {e}")
# Post-save signal to generate the thumbnail after the object is saved
@receiver(post_save, sender=InstructorDocuments)
def generate_thumbnail(sender, instance, created, **kwargs):
    if created:  # Only generate the thumbnail when the document is first created
        if instance.source_type == 'image':
            instance._generate_image_thumbnail()
        elif instance.source_type == 'document':
            instance._generate_document_thumbnail()
        elif instance.source_type == 'video':
            instance._generate_video_thumbnail()

        # Save the instance again after generating the thumbnail
        instance.save()


class UserCourse(models.Model):
    # user = models.ForeignKey(
    #     User, related_name='user_course', on_delete=models.CASCADE, blank=True, null=True)
    students = models.ManyToManyField(User, related_name= 'user_course')
    course = models.ForeignKey(
        'Course', related_name='user_course', on_delete=models.CASCADE, null=True, blank=True)
    # is_paid = models.BooleanField(default=False)
    instructor = models.ForeignKey(
        'Instructor', related_name='user_course', on_delete=models.CASCADE, null=True, blank=True)
    status_choices = (
        ('Pending', 'Pending'),
        ('Approved', 'Approved')
    )
    approval_status = models.CharField(
        max_length=128, choices=status_choices, default='Pending')  # Pending, Approved
    rating = models.DecimalField(
        max_digits=2, decimal_places=1, null=True, blank=True)
    hold_access = models.BooleanField(default=False)

    # new addition 29-01-25
    name = models.CharField(max_length=128, null=True, blank=True)

    # new addition 09-03-2025
    duration = models.IntegerField(blank=True, null=True)                                # hours
    class_completed = models.IntegerField(blank=True, null=True)                         # 1 class = 1 hour
    

    # def __str__(self):
    #     return f'{self.user.first_name} {self.user.last_name} | {self.course.title} | {self.approval_status}'


class HoldWeek(models.Model):
    usercourse = models.ForeignKey(
        'UserCourse', related_name='hold_week', on_delete=models.CASCADE)
    week = models.TextField()


class InstructorHoldWeek(models.Model):
    instructor = models.ForeignKey('Instructor', related_name='instructor_hold_week', on_delete=models.CASCADE, blank=True, null=True)
    course = models.ForeignKey('Course', related_name='instructor_hold_week', on_delete=models.SET_NULL, null=True, blank=True)
    week = models.TextField()


class DiscussionPost(models.Model):
    usercourse = models.ForeignKey(
        'UserCourse', related_name='discussion_posts', on_delete=models.CASCADE)
    user = models.ForeignKey(User, related_name='discussion_posts', on_delete=models.SET_NULL, null=True)
    title = models.CharField(max_length=200)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    edited_at = models.DateTimeField(auto_now=True)
    is_edited = models.BooleanField(default=False)
    is_published = models.BooleanField(default=False)


class DiscussionPostAttachment(models.Model):
    discussion_post = models.ForeignKey('DiscussionPost', related_name='attachments', on_delete=models.CASCADE)
    attachment = models.FileField(upload_to=discussion_post_file_upload_path, max_length=256, blank=True, null=True)


class DiscussionReply(models.Model):
    user = models.ForeignKey(User, related_name='discussion_replies', on_delete=models.SET_NULL, null=True)
    discussion_post = models.ForeignKey('DiscussionPost', related_name='discussion_replies', on_delete=models.CASCADE)
    parent_reply = models.ForeignKey('self', related_name='child_replies', on_delete=models.CASCADE, null=True)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    edited_at = models.DateTimeField(auto_now=True)
    is_edited = models.BooleanField(default=False)
    is_deleted = models.BooleanField(default=False)


class DiscussionReplyAttachment(models.Model):
    discussion_reply = models.ForeignKey('DiscussionReply', related_name='attachments', on_delete=models.CASCADE, null=True)
    attachment = models.FileField(upload_to=discussion_reply_file_upload_path, max_length=256, blank=True, null=True)


class DiscussionUpvote(models.Model):
    user = models.ForeignKey(User, related_name='discussion_upvotes', on_delete=models.CASCADE)
    discussion_post = models.ForeignKey('DiscussionPost', related_name='discussion_upvotes', on_delete=models.CASCADE, null=True)
    discussion_reply = models.ForeignKey('DiscussionReply', related_name='discussion_upvotes', on_delete=models.CASCADE, null=True)
    created_at = models.DateTimeField(auto_now_add=True)


class DiscussionPostViewCount(models.Model):
    user = models.ForeignKey(User, related_name='discussion_post_views', on_delete=models.SET_NULL, null=True)
    discussion_post = models.ForeignKey('DiscussionPost', related_name='views', on_delete=models.CASCADE)


class VideoRecord(models.Model):
    title = models.CharField(max_length=128)
    user = models.ForeignKey(User, related_name='recorded_videos', on_delete=models.SET_NULL, null=True)
    usercourse = models.ForeignKey(
        'UserCourse', related_name='video_record', on_delete=models.CASCADE, default=False)
    thumbnail = models.FileField(blank=True, null=True)
    video = models.FileField(upload_to=recorded_video_file_upload_path, blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True)

class Notepad(models.Model):
    usercourse = models.ForeignKey(
        'UserCourse', related_name='notepad', on_delete=models.CASCADE, default=False)
    user = models.ForeignKey(User, related_name='notepad', on_delete=models.SET_NULL, null=True)
    note = models.TextField()
    is_published = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)



class AnnouncementPost(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    course = models.ForeignKey('Course', related_name='announcements', on_delete=models.CASCADE)
    user = models.ForeignKey(User, related_name='announcements', on_delete=models.SET_NULL, null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    edited_at = models.DateTimeField(auto_now=True)
    is_edited = models.BooleanField(default=False)
    is_published = models.BooleanField(default=False)


class AnnouncementPostAttachment(models.Model):
    announcement_post = models.ForeignKey('AnnouncementPost', related_name='attachments', on_delete=models.CASCADE)
    attachment = models.FileField(upload_to=announcement_post_file_upload_path, max_length=256, blank=True, null=True)


class AnnouncementUpvote(models.Model):
    user = models.ForeignKey(User, related_name='announcement_upvotes', on_delete=models.CASCADE)
    announcement_post = models.ForeignKey('AnnouncementPost', related_name='announcement_upvotes', on_delete=models.CASCADE, null=True)
    created_at = models.DateTimeField(auto_now_add=True)


class AnnouncementPostViewCount(models.Model):
    user = models.ForeignKey(User, related_name='announcement_post_views', on_delete=models.SET_NULL, null=True)
    announcement_post = models.ForeignKey('AnnouncementPost', related_name='views', on_delete=models.CASCADE)


class OnlineMeeting(models.Model):
    usercourse = models.ForeignKey(
        'UserCourse', related_name='online_meeting', on_delete=models.CASCADE, null= True)
    client = models.CharField(max_length=32)
    topic = models.CharField(max_length=512)
    meeting_url = models.CharField(max_length=256, null=True)
    meeting_id = models.CharField(max_length=128, null=True)
    passcode = models.CharField(max_length=32, null=True)
    start_time = models.DateTimeField()
    duration = models.TextField(blank=True, null=True)
    details = models.CharField(max_length=32)
    is_active = models.BooleanField(default=False)

    created_at = models.DateTimeField(auto_now_add=True)
    edited_at = models.DateTimeField(auto_now=True)

# capture instructor live class join
class InstructorMeetingJoin(models.Model):
    live_class = models.ForeignKey('OnlineMeeting', on_delete=models.CASCADE, related_name='instructors')
    instructor = models.ForeignKey('Instructor', related_name='instructor_meeting_join', on_delete=models.CASCADE, blank=True, null=True)
    joined_at = models.DateTimeField(auto_now_add=True)
    summary = models.TextField(blank=True, null=True)

# capture student live class join
class StudentMeetingJoin(models.Model):
    live_class = models.ForeignKey('OnlineMeeting', on_delete=models.CASCADE, related_name='students')
    student = models.ForeignKey(User, on_delete=models.CASCADE, related_name='student_meeting_join')
    joined_at = models.DateTimeField(auto_now_add=True)



class GradeConfig(models.Model):
    course = models.ForeignKey('Course', related_name='grade_configs', on_delete=models.CASCADE)
    grade = models.CharField(max_length=16)
    start_point = models.IntegerField()
    end_point = models.IntegerField()

    created_at = models.DateTimeField(auto_now_add=True)
    edited_at = models.DateTimeField(auto_now=True)



class Testimonial(models.Model):
    user = models.ForeignKey(
        User, on_delete=models.CASCADE, blank=True, null=True)
    course = models.ForeignKey('Course', related_name='course_testimonial', on_delete=models.CASCADE, blank=True, null=True)
    instructor = models.ForeignKey('Instructor', related_name='course_instructor', on_delete=models.SET_NULL, blank=True, null=True)
    testimonial = models.CharField(max_length=1024, blank=True, null=True)
    rating = models.IntegerField(null=True, blank=True)


class PromoCode(models.Model):
    code = models.CharField(max_length=100, blank=True, null=True)
    discount_amount = models.DecimalField(max_digits=10, decimal_places=2)  # Discount amount or percentage
    discount_type = models.CharField(
        max_length=15,
        choices=[('Fixed Amount', 'Fixed Amount'), ('Percentage', 'Percentage')],
        default='fixed'
    )
    valid_from = models.DateTimeField(blank=True, null=True) 
    valid_to = models.DateTimeField(blank=True, null=True)
    total_count = models.IntegerField(blank=True, null=True)
    taken_count = models.IntegerField(blank=True, null=True)
    code_status = models.CharField(
        max_length=10,
        choices=[('Active', 'Active'), ('Inactive', 'Inactive')],
        default='Inactive'
    )

    created_at = models.DateTimeField(auto_now_add=True)
    edited_at = models.DateTimeField(auto_now=True)
    

class Consultation(models.Model):
    name = models.CharField(max_length=100)
    email = models.EmailField()
    preferred_time = models.CharField(max_length=100)
    details = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.name
