import re
from django.conf import settings
from django.core.exceptions import ValidationError
from django.db import models


def _validate_file_size(value):
    max_mb = getattr(settings, 'MAX_CONTENT_FILE_SIZE_MB', 50)
    if value.size > max_mb * 1024 * 1024:
        raise ValidationError(f'File too large. Maximum allowed size is {max_mb} MB.')


class CourseMaterial(models.Model):
    YOUTUBE = 'youtube'
    UPLOAD = 'upload'
    LINK = 'link'
    NOTE = 'note'
    TYPE_CHOICES = [
        (YOUTUBE, 'YouTube Video'),
        (UPLOAD, 'File Upload'),
        (LINK, 'External Link'),
        (NOTE, 'Text / Notes'),
    ]

    course = models.ForeignKey('courses.Course', on_delete=models.CASCADE, related_name='materials')
    title = models.CharField(max_length=200)
    material_type = models.CharField(max_length=10, choices=TYPE_CHOICES)
    description = models.TextField(blank=True)
    youtube_url = models.URLField(blank=True, verbose_name='YouTube URL')
    external_url = models.URLField(blank=True, verbose_name='External Link URL')
    file = models.FileField(
        upload_to='course_materials/%Y/%m/',
        blank=True, null=True,
        validators=[_validate_file_size],
    )
    text_content = models.TextField(blank=True, verbose_name='Text / Notes Content')
    order = models.PositiveIntegerField(default=0)
    is_published = models.BooleanField(default=False)
    uploaded_by = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.SET_NULL,
        null=True, blank=True, related_name='uploaded_materials',
    )
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ['order', 'created_at']

    def __str__(self):
        return f"{self.title} ({self.get_material_type_display()}) — {self.course}"

    @property
    def youtube_video_id(self):
        if not self.youtube_url:
            return ''
        match = re.search(
            r'(?:youtube\.com/watch\?v=|youtu\.be/|youtube\.com/embed/)([a-zA-Z0-9_-]{11})',
            self.youtube_url,
        )
        return match.group(1) if match else ''

    @property
    def youtube_embed_url(self):
        vid_id = self.youtube_video_id
        if vid_id:
            return f'https://www.youtube-nocookie.com/embed/{vid_id}?rel=0&modestbranding=1'
        return self.youtube_url

    @property
    def file_extension(self):
        if self.file:
            name = self.file.name
            return name.rsplit('.', 1)[-1].lower() if '.' in name else ''
        return ''

    @property
    def is_pdf(self):
        return self.file_extension == 'pdf'

    @property
    def icon_class(self):
        return {
            self.YOUTUBE: 'fa-brands fa-youtube text-danger',
            self.UPLOAD: 'fa-solid fa-file-arrow-down text-primary',
            self.LINK: 'fa-solid fa-link text-info',
            self.NOTE: 'fa-solid fa-file-lines text-secondary',
        }.get(self.material_type, 'fa-solid fa-circle')


class Assignment(models.Model):
    course = models.ForeignKey('courses.Course', on_delete=models.CASCADE, related_name='assignments')
    title = models.CharField(max_length=200)
    description = models.TextField(blank=True)
    due_date = models.DateTimeField(null=True, blank=True)
    is_published = models.BooleanField(default=False)
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.SET_NULL,
        null=True, blank=True, related_name='created_assignments',
    )
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ['-created_at']

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

    @property
    def is_overdue(self):
        from django.utils import timezone
        return self.due_date and timezone.now() > self.due_date


class Submission(models.Model):
    assignment = models.ForeignKey(Assignment, on_delete=models.CASCADE, related_name='submissions')
    student = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='submissions',
    )
    file = models.FileField(
        upload_to='submissions/%Y/%m/',
        null=True, blank=True,
        validators=[_validate_file_size],
    )
    notes = models.TextField(blank=True, verbose_name='Submission notes')
    submitted_at = models.DateTimeField(auto_now_add=True)
    is_late = models.BooleanField(default=False)

    grade = models.CharField(max_length=1, blank=True, choices=[
        ('A', 'A — Distinction'), ('B', 'B — Credit'), ('C', 'C — Pass'),
        ('D', 'D — Partial Pass'), ('F', 'F — Fail'),
    ])
    feedback = models.TextField(blank=True)
    graded_by = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.SET_NULL,
        null=True, blank=True, related_name='graded_submissions',
    )
    graded_at = models.DateTimeField(null=True, blank=True)

    class Meta:
        ordering = ['-submitted_at']
        unique_together = [['assignment', 'student']]

    def __str__(self):
        return f"{self.student.get_full_name()} → {self.assignment.title}"

    @property
    def grade_color(self):
        return {'A': 'success', 'B': 'primary', 'C': 'info', 'D': 'warning', 'F': 'danger'}.get(self.grade, 'secondary')


class Quiz(models.Model):
    course = models.OneToOneField('courses.Course', on_delete=models.CASCADE, related_name='quiz')
    title = models.CharField(max_length=200)
    description = models.TextField(blank=True)
    is_enabled = models.BooleanField(default=True)
    max_attempts = models.PositiveIntegerField(
        default=3,
        help_text='Maximum attempts per student. Set 0 for unlimited.',
    )
    pass_score = models.PositiveIntegerField(
        default=60,
        help_text='Minimum percentage score to pass (0-100).',
    )
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.SET_NULL,
        null=True, blank=True, related_name='created_quizzes',
    )
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        verbose_name_plural = 'quizzes'

    def __str__(self):
        return f"Quiz: {self.title} — {self.course}"

    @property
    def question_count(self):
        return self.questions.count()


class QuizQuestion(models.Model):
    quiz = models.ForeignKey(Quiz, on_delete=models.CASCADE, related_name='questions')
    question_text = models.TextField()
    order = models.PositiveIntegerField(default=0)

    class Meta:
        ordering = ['order', 'id']

    def __str__(self):
        return f"Q{self.order}: {self.question_text[:60]}"


class QuizChoice(models.Model):
    question = models.ForeignKey(QuizQuestion, on_delete=models.CASCADE, related_name='choices')
    choice_text = models.CharField(max_length=500)
    is_correct = models.BooleanField(default=False)

    def __str__(self):
        prefix = '[correct] ' if self.is_correct else ''
        return f"{prefix}{self.choice_text[:60]}"


class QuizAttempt(models.Model):
    student = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='quiz_attempts',
    )
    quiz = models.ForeignKey(Quiz, on_delete=models.CASCADE, related_name='attempts')
    score = models.DecimalField(max_digits=5, decimal_places=2, help_text='Percentage score')
    passed = models.BooleanField(default=False)
    answers = models.JSONField(default=dict, help_text='Map of question_id to choice_id')
    completed_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ['-completed_at']

    def __str__(self):
        return f"{self.student.get_full_name()} — {self.quiz.title} — {self.score}%"
