from django import forms
from django.conf import settings
from django.contrib import messages
from django.contrib.auth import get_user_model
from django.contrib.auth.mixins import LoginRequiredMixin
from django.db.models import Sum
from django.shortcuts import get_object_or_404, redirect, render
from django.views import View

from accounts.mixins import StudentRequiredMixin
from courses.models import Course
from payments.models import Payment
from accounts.mixins import TeacherRequiredMixin, AdminRequiredMixin
from admissions.models import Enrollment
from .models import CourseMaterial, Quiz, QuizAttempt, QuizChoice, QuizQuestion, Assignment, Submission

User = get_user_model()


# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

def _can_manage_content(user, course):
    """True if user may manage content for this course."""
    if user.role in (User.ADMIN, User.SUPER_ADMIN):
        return True
    if user.role == User.TEACHER:
        profile = getattr(user, 'teacher_profile', None)
        return profile is not None and profile.programs.filter(pk=course.program_id).exists()
    return False


def _student_has_access(enrollment):
    """True if student may access course content.

    Checks the admin override first, then falls back to the payment threshold.
    """
    override = enrollment.content_access_override
    if override == 'enabled':
        return True
    if override == 'disabled':
        return False
    # default: check payment threshold
    threshold = enrollment.program.content_access_percentage
    if threshold == 0:
        return True
    total_fees = float(
        (enrollment.program.tuition_fee or 0)
        + (enrollment.program.practical_fee or 0)
        + (enrollment.program.assessment_fee or 0)
        + (enrollment.program.exam_fee or 0)
    )
    if total_fees == 0:
        return True
    total_paid = float(
        Payment.objects.filter(enrollment=enrollment)
        .aggregate(t=Sum('amount'))['t'] or 0
    )
    return (total_paid / total_fees * 100) >= threshold


def _access_denied_message(enrollment):
    """Return the correct user-facing warning when content access is blocked."""
    if enrollment.content_access_override == 'disabled':
        return 'Course content has been temporarily restricted for your account. Please contact the administration.'
    return 'Pay your outstanding fees to unlock course content.'


def _payment_summary(enrollment):
    """Return dict with payment stats for the locked-content screen."""
    program = enrollment.program
    total_fees = float(
        (program.tuition_fee or 0)
        + (program.practical_fee or 0)
        + (program.assessment_fee or 0)
        + (program.exam_fee or 0)
    )
    total_paid = float(
        Payment.objects.filter(enrollment=enrollment)
        .aggregate(t=Sum('amount'))['t'] or 0
    )
    threshold = program.content_access_percentage
    paid_pct = round(total_paid / total_fees * 100, 1) if total_fees else 100
    still_needed = max(0.0, threshold / 100 * total_fees - total_paid)
    return {
        'total_fees': total_fees,
        'total_paid': total_paid,
        'paid_pct': paid_pct,
        'threshold': threshold,
        'still_needed': still_needed,
    }


# ---------------------------------------------------------------------------
# Forms
# ---------------------------------------------------------------------------

class _MaterialForm(forms.ModelForm):
    class Meta:
        model = CourseMaterial
        fields = [
            'title', 'material_type', 'description',
            'youtube_url', 'external_url', 'file', 'text_content',
            'order', 'is_published',
        ]
        widgets = {
            'description': forms.Textarea(attrs={'rows': 2}),
            'text_content': forms.Textarea(attrs={'rows': 8}),
        }

    def __init__(self, *args, include_order=False, **kwargs):
        super().__init__(*args, **kwargs)
        from crispy_forms.helper import FormHelper
        from crispy_forms.layout import Column, Field, Layout, Row, Submit
        if not include_order:
            self.fields['order'].required = False
        self.helper = FormHelper()

        bottom_row = (
            Row(
                Column('order', css_class='col-md-3'),
                Column(Field('is_published'), css_class='col-md-9 pt-4'),
            )
            if include_order
            else Field('is_published')
        )
        self.helper.layout = Layout(
            Row(
                Column('title', css_class='col-md-8'),
                Column('material_type', css_class='col-md-4'),
            ),
            'description',
            'youtube_url',
            'external_url',
            'file',
            'text_content',
            bottom_row,
            Submit('submit', 'Save Material', css_class='btn btn-primary mt-2'),
        )

    def clean(self):
        cleaned = super().clean()
        t = cleaned.get('material_type')
        if t == CourseMaterial.YOUTUBE and not cleaned.get('youtube_url'):
            self.add_error('youtube_url', 'Enter a YouTube URL.')
        elif t == CourseMaterial.LINK and not cleaned.get('external_url'):
            self.add_error('external_url', 'Enter the external link URL.')
        elif t == CourseMaterial.UPLOAD:
            has_existing = self.instance.pk and self.instance.file
            if not cleaned.get('file') and not has_existing:
                self.add_error('file', 'Upload a file.')
        elif t == CourseMaterial.NOTE and not cleaned.get('text_content'):
            self.add_error('text_content', 'Enter the text / notes content.')
        return cleaned


class _QuizSettingsForm(forms.ModelForm):
    class Meta:
        model = Quiz
        fields = ['title', 'description', 'is_enabled', 'max_attempts', 'pass_score']
        widgets = {'description': forms.Textarea(attrs={'rows': 2})}

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        from crispy_forms.helper import FormHelper
        from crispy_forms.layout import Column, Field, Layout, Row, Submit
        self.helper = FormHelper()
        self.helper.layout = Layout(
            'title',
            'description',
            Row(
                Column('max_attempts', css_class='col-md-4'),
                Column('pass_score', css_class='col-md-4'),
                Column(Field('is_enabled'), css_class='col-md-4 pt-4'),
            ),
            Submit('submit', 'Save Quiz Settings', css_class='btn btn-primary mt-2'),
        )


class _QuizQuestionForm(forms.Form):
    question_text = forms.CharField(
        label='Question', widget=forms.Textarea(attrs={'rows': 3})
    )
    choice_1 = forms.CharField(max_length=500, label='Choice A')
    choice_2 = forms.CharField(max_length=500, label='Choice B')
    choice_3 = forms.CharField(max_length=500, label='Choice C')
    choice_4 = forms.CharField(max_length=500, label='Choice D')
    correct_choice = forms.ChoiceField(
        choices=[('1', 'A is correct'), ('2', 'B is correct'),
                 ('3', 'C is correct'), ('4', 'D is correct')],
        widget=forms.RadioSelect,
        label='Correct Answer',
    )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        from crispy_forms.helper import FormHelper
        from crispy_forms.layout import Column, Field, Layout, Row, Submit
        self.helper = FormHelper()
        self.helper.layout = Layout(
            'question_text',
            Row(
                Column('choice_1', css_class='col-md-6'),
                Column('choice_2', css_class='col-md-6'),
            ),
            Row(
                Column('choice_3', css_class='col-md-6'),
                Column('choice_4', css_class='col-md-6'),
            ),
            Field('correct_choice'),
            Submit('submit', 'Save Question', css_class='btn btn-primary mt-2'),
        )


# ---------------------------------------------------------------------------
# Teacher / Admin — Course content management
# ---------------------------------------------------------------------------

class CourseContentView(LoginRequiredMixin, View):
    template_name = 'content/course_content.html'

    def dispatch(self, request, *args, **kwargs):
        self.course = get_object_or_404(Course, pk=kwargs['course_pk'])
        if not _can_manage_content(request.user, self.course):
            messages.error(request, 'You do not have permission to manage content for this course.')
            return redirect('portal:teacher_dashboard')
        return super().dispatch(request, *args, **kwargs)

    def get(self, request, course_pk):
        materials = CourseMaterial.objects.filter(course=self.course).order_by('order', 'created_at')
        quiz = getattr(self.course, 'quiz', None)
        return render(request, self.template_name, {
            'course': self.course,
            'materials': materials,
            'quiz': quiz,
        })


class MaterialCreateView(LoginRequiredMixin, View):
    template_name = 'content/material_form.html'

    def _course(self, pk, user):
        course = get_object_or_404(Course, pk=pk)
        return course if _can_manage_content(user, course) else None

    def get(self, request, course_pk):
        course = self._course(course_pk, request.user)
        if not course:
            messages.error(request, 'Permission denied.')
            return redirect('portal:teacher_dashboard')
        return render(request, self.template_name, {
            'form': _MaterialForm(), 'course': course, 'action': 'Add',
            'max_file_size_mb': getattr(settings, 'MAX_CONTENT_FILE_SIZE_MB', 50),
        })

    def post(self, request, course_pk):
        course = self._course(course_pk, request.user)
        if not course:
            messages.error(request, 'Permission denied.')
            return redirect('portal:teacher_dashboard')
        form = _MaterialForm(request.POST, request.FILES)
        if form.is_valid():
            m = form.save(commit=False)
            m.course = course
            m.uploaded_by = request.user
            # Auto-assign order: next after the highest existing order
            max_order = CourseMaterial.objects.filter(course=course).order_by('-order').values_list('order', flat=True).first()
            m.order = (max_order or 0) + 1
            m.save()
            messages.success(request, f'"{m.title}" added.')
            return redirect('content:course_content', course_pk=course.pk)
        return render(request, self.template_name, {
            'form': form, 'course': course, 'action': 'Add',
            'max_file_size_mb': getattr(settings, 'MAX_CONTENT_FILE_SIZE_MB', 50),
        })


class MaterialUpdateView(LoginRequiredMixin, View):
    template_name = 'content/material_form.html'

    def _material(self, pk, user):
        m = get_object_or_404(CourseMaterial, pk=pk)
        return m if _can_manage_content(user, m.course) else None

    def get(self, request, pk):
        m = self._material(pk, request.user)
        if not m:
            messages.error(request, 'Permission denied.')
            return redirect('portal:teacher_dashboard')
        return render(request, self.template_name, {
            'form': _MaterialForm(instance=m, include_order=True),
            'course': m.course, 'material': m, 'action': 'Edit',
            'max_file_size_mb': getattr(settings, 'MAX_CONTENT_FILE_SIZE_MB', 50),
        })

    def post(self, request, pk):
        m = self._material(pk, request.user)
        if not m:
            messages.error(request, 'Permission denied.')
            return redirect('portal:teacher_dashboard')
        form = _MaterialForm(request.POST, request.FILES, instance=m, include_order=True)
        if form.is_valid():
            form.save()
            messages.success(request, f'"{m.title}" updated.')
            return redirect('content:course_content', course_pk=m.course_id)
        return render(request, self.template_name, {
            'form': form, 'course': m.course, 'material': m, 'action': 'Edit',
            'max_file_size_mb': getattr(settings, 'MAX_CONTENT_FILE_SIZE_MB', 50),
            'include_order': True,
        })


class MaterialDeleteView(LoginRequiredMixin, View):
    def post(self, request, pk):
        m = get_object_or_404(CourseMaterial, pk=pk)
        if not _can_manage_content(request.user, m.course):
            messages.error(request, 'Permission denied.')
            return redirect('portal:teacher_dashboard')
        course_pk = m.course_id
        if m.file:
            m.file.delete(save=False)
        title = m.title
        m.delete()
        messages.success(request, f'"{title}" deleted.')
        return redirect('content:course_content', course_pk=course_pk)


class MaterialToggleView(LoginRequiredMixin, View):
    def post(self, request, pk):
        m = get_object_or_404(CourseMaterial, pk=pk)
        if not _can_manage_content(request.user, m.course):
            messages.error(request, 'Permission denied.')
            return redirect('portal:teacher_dashboard')
        m.is_published = not m.is_published
        m.save(update_fields=['is_published'])
        status = 'published' if m.is_published else 'unpublished'
        messages.success(request, f'"{m.title}" {status}.')
        return redirect('content:course_content', course_pk=m.course_id)


# ---------------------------------------------------------------------------
# Teacher / Admin — Quiz builder
# ---------------------------------------------------------------------------

class QuizBuilderView(LoginRequiredMixin, View):
    template_name = 'content/quiz_builder.html'

    def _course(self, pk, user):
        course = get_object_or_404(Course, pk=pk)
        return course if _can_manage_content(user, course) else None

    def get(self, request, course_pk):
        course = self._course(course_pk, request.user)
        if not course:
            messages.error(request, 'Permission denied.')
            return redirect('portal:teacher_dashboard')
        quiz = getattr(course, 'quiz', None)
        return render(request, self.template_name, {
            'course': course,
            'quiz': quiz,
            'quiz_form': _QuizSettingsForm(instance=quiz),
            'questions': list(quiz.questions.prefetch_related('choices').all()) if quiz else [],
        })

    def post(self, request, course_pk):
        course = self._course(course_pk, request.user)
        if not course:
            messages.error(request, 'Permission denied.')
            return redirect('portal:teacher_dashboard')
        quiz = getattr(course, 'quiz', None)
        form = _QuizSettingsForm(request.POST, instance=quiz)
        if form.is_valid():
            q = form.save(commit=False)
            q.course = course
            if not q.pk:
                q.created_by = request.user
            q.save()
            messages.success(request, 'Quiz settings saved.')
            return redirect('content:quiz_builder', course_pk=course.pk)
        return render(request, self.template_name, {
            'course': course,
            'quiz': quiz,
            'quiz_form': form,
            'questions': list(quiz.questions.prefetch_related('choices').all()) if quiz else [],
        })


class QuizQuestionCreateView(LoginRequiredMixin, View):
    template_name = 'content/question_form.html'

    def _quiz(self, pk, user):
        quiz = get_object_or_404(Quiz, pk=pk)
        return quiz if _can_manage_content(user, quiz.course) else None

    def get(self, request, quiz_pk):
        quiz = self._quiz(quiz_pk, request.user)
        if not quiz:
            messages.error(request, 'Permission denied.')
            return redirect('portal:teacher_dashboard')
        return render(request, self.template_name, {
            'form': _QuizQuestionForm(), 'quiz': quiz, 'action': 'Add',
        })

    def post(self, request, quiz_pk):
        quiz = self._quiz(quiz_pk, request.user)
        if not quiz:
            messages.error(request, 'Permission denied.')
            return redirect('portal:teacher_dashboard')
        form = _QuizQuestionForm(request.POST)
        if form.is_valid():
            d = form.cleaned_data
            question = QuizQuestion.objects.create(
                quiz=quiz,
                question_text=d['question_text'],
                order=quiz.questions.count() + 1,
            )
            correct = int(d['correct_choice'])
            for i in range(1, 5):
                QuizChoice.objects.create(
                    question=question,
                    choice_text=d[f'choice_{i}'],
                    is_correct=(i == correct),
                )
            messages.success(request, 'Question added.')
            return redirect('content:quiz_builder', course_pk=quiz.course_id)
        return render(request, self.template_name, {
            'form': form, 'quiz': quiz, 'action': 'Add',
        })


class QuizQuestionUpdateView(LoginRequiredMixin, View):
    template_name = 'content/question_form.html'

    def _question(self, pk, user):
        q = get_object_or_404(QuizQuestion, pk=pk)
        return q if _can_manage_content(user, q.quiz.course) else None

    def get(self, request, pk):
        question = self._question(pk, request.user)
        if not question:
            messages.error(request, 'Permission denied.')
            return redirect('portal:teacher_dashboard')
        choices = list(question.choices.all())
        while len(choices) < 4:
            choices.append(None)
        correct_idx = next(
            (str(i + 1) for i, c in enumerate(choices) if c and c.is_correct), '1'
        )
        initial = {'question_text': question.question_text, 'correct_choice': correct_idx}
        for i, c in enumerate(choices, 1):
            initial[f'choice_{i}'] = c.choice_text if c else ''
        return render(request, self.template_name, {
            'form': _QuizQuestionForm(initial=initial),
            'quiz': question.quiz,
            'question': question,
            'action': 'Edit',
        })

    def post(self, request, pk):
        question = self._question(pk, request.user)
        if not question:
            messages.error(request, 'Permission denied.')
            return redirect('portal:teacher_dashboard')
        form = _QuizQuestionForm(request.POST)
        if form.is_valid():
            d = form.cleaned_data
            question.question_text = d['question_text']
            question.save(update_fields=['question_text'])
            question.choices.all().delete()
            correct = int(d['correct_choice'])
            for i in range(1, 5):
                QuizChoice.objects.create(
                    question=question,
                    choice_text=d[f'choice_{i}'],
                    is_correct=(i == correct),
                )
            messages.success(request, 'Question updated.')
            return redirect('content:quiz_builder', course_pk=question.quiz.course_id)
        return render(request, self.template_name, {
            'form': form, 'quiz': question.quiz, 'question': question, 'action': 'Edit',
        })


class QuizQuestionDeleteView(LoginRequiredMixin, View):
    def post(self, request, pk):
        question = get_object_or_404(QuizQuestion, pk=pk)
        if not _can_manage_content(request.user, question.quiz.course):
            messages.error(request, 'Permission denied.')
            return redirect('portal:teacher_dashboard')
        course_pk = question.quiz.course_id
        question.delete()
        messages.success(request, 'Question deleted.')
        return redirect('content:quiz_builder', course_pk=course_pk)


class QuizAttemptResetView(LoginRequiredMixin, View):
    def post(self, request, quiz_pk, student_pk):
        quiz = get_object_or_404(Quiz, pk=quiz_pk)
        if not _can_manage_content(request.user, quiz.course):
            messages.error(request, 'Permission denied.')
            return redirect('portal:teacher_dashboard')
        student = get_object_or_404(User, pk=student_pk)
        deleted, _ = QuizAttempt.objects.filter(student=student, quiz=quiz).delete()
        messages.success(request, f'Attempts reset for {student.get_full_name()} ({deleted} removed).')
        return redirect('content:quiz_builder', course_pk=quiz.course_id)


# ---------------------------------------------------------------------------
# Student — course content & quiz
# ---------------------------------------------------------------------------

class StudentCourseDetailView(StudentRequiredMixin, View):
    template_name = 'content/student_course_detail.html'

    def get(self, request, course_pk):
        enrollment = getattr(request.user, 'enrollment', None)
        if not enrollment:
            messages.error(request, 'No active enrollment found.')
            return redirect('portal:student_dashboard')
        course = get_object_or_404(
            Course, pk=course_pk, program=enrollment.program, is_active=True
        )
        if not _student_has_access(enrollment):
            messages.warning(request, _access_denied_message(enrollment))
            return redirect('portal:student_payments')

        materials = list(
            CourseMaterial.objects.filter(course=course, is_published=True)
            .order_by('order', 'created_at')
        )
        quiz, quiz_attempts, quiz_last_score, quiz_can_attempt = None, 0, None, False
        raw_quiz = getattr(course, 'quiz', None)
        if raw_quiz and raw_quiz.is_enabled and raw_quiz.question_count > 0:
            quiz = raw_quiz
            quiz_attempts = QuizAttempt.objects.filter(student=request.user, quiz=quiz).count()
            last = QuizAttempt.objects.filter(student=request.user, quiz=quiz).first()
            quiz_last_score = last.score if last else None
            quiz_can_attempt = (quiz.max_attempts == 0) or (quiz_attempts < quiz.max_attempts)

        return render(request, self.template_name, {
            'course': course,
            'enrollment': enrollment,
            'materials': materials,
            'quiz': quiz,
            'quiz_attempts': quiz_attempts,
            'quiz_last_score': quiz_last_score,
            'quiz_can_attempt': quiz_can_attempt,
        })


class StudentQuizView(StudentRequiredMixin, View):
    template_name = 'content/student_quiz.html'

    def _setup(self, request, course_pk):
        enrollment = getattr(request.user, 'enrollment', None)
        if not enrollment:
            return None, None, None
        course = get_object_or_404(Course, pk=course_pk, program=enrollment.program, is_active=True)
        if not _student_has_access(enrollment):
            # Return enrollment so callers can generate the right message
            return enrollment, None, None
        quiz = get_object_or_404(Quiz, course=course, is_enabled=True)
        return enrollment, course, quiz

    def get(self, request, course_pk):
        enrollment, course, quiz = self._setup(request, course_pk)
        if not enrollment:
            return redirect('portal:student_payments')
        if not course:
            messages.warning(request, _access_denied_message(enrollment))
            return redirect('portal:student_payments')
        attempts = QuizAttempt.objects.filter(student=request.user, quiz=quiz).count()
        if quiz.max_attempts > 0 and attempts >= quiz.max_attempts:
            messages.warning(request, f'You have used all {quiz.max_attempts} attempt(s) for this quiz.')
            return redirect('content:student_course_detail', course_pk=course_pk)
        return render(request, self.template_name, {
            'course': course,
            'quiz': quiz,
            'questions': quiz.questions.prefetch_related('choices').all(),
            'attempts_taken': attempts,
        })

    def post(self, request, course_pk):
        enrollment, course, quiz = self._setup(request, course_pk)
        if not enrollment:
            return redirect('portal:student_payments')
        if not course:
            messages.warning(request, _access_denied_message(enrollment))
            return redirect('portal:student_payments')
        attempts = QuizAttempt.objects.filter(student=request.user, quiz=quiz).count()
        if quiz.max_attempts > 0 and attempts >= quiz.max_attempts:
            messages.warning(request, 'No attempts remaining.')
            return redirect('content:student_course_detail', course_pk=course_pk)

        questions = list(quiz.questions.prefetch_related('choices').all())
        answers, correct_count = {}, 0
        for question in questions:
            choice_id_str = request.POST.get(f'q_{question.id}')
            if choice_id_str:
                try:
                    cid = int(choice_id_str)
                    answers[str(question.id)] = cid
                    if question.choices.filter(pk=cid, is_correct=True).exists():
                        correct_count += 1
                except (ValueError, TypeError):
                    pass

        total = len(questions)
        score = round(correct_count / total * 100, 2) if total else 0
        passed = score >= quiz.pass_score
        attempt = QuizAttempt.objects.create(
            student=request.user, quiz=quiz,
            score=score, passed=passed, answers=answers,
        )

        # Annotate each question with per-choice result flags for template display
        result_questions = []
        for q in questions:
            chosen_id = answers.get(str(q.id))
            annotated_choices = []
            for c in q.choices.all():
                annotated_choices.append({
                    'pk': c.pk,
                    'choice_text': c.choice_text,
                    'is_correct': c.is_correct,
                    'was_chosen': (c.pk == chosen_id),
                })
            result_questions.append({'question': q, 'choices': annotated_choices})

        return render(request, 'content/student_quiz_result.html', {
            'course': course,
            'quiz': quiz,
            'attempt': attempt,
            'correct_count': correct_count,
            'total': total,
            'result_questions': result_questions,
            'new_attempts_taken': attempts + 1,
        })


# ---------------------------------------------------------------------------
# Assignments — Teacher (create / list submissions / grade)
# ---------------------------------------------------------------------------

class _AssignmentForm(forms.ModelForm):
    class Meta:
        model = Assignment
        fields = ['title', 'description', 'due_date', 'is_published']
        widgets = {
            'description': forms.Textarea(attrs={'rows': 4}),
            'due_date': forms.DateTimeInput(attrs={'type': 'datetime-local'}),
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        from crispy_forms.helper import FormHelper
        from crispy_forms.layout import Layout, Submit
        self.helper = FormHelper()
        self.helper.layout = Layout('title', 'description', 'due_date', 'is_published',
                                    Submit('submit', 'Save Assignment', css_class='btn btn-primary mt-2'))


def _teacher_can_manage_course(user, course):
    if user.role in (User.ADMIN, User.SUPER_ADMIN):
        return True
    if user.role == User.TEACHER:
        profile = getattr(user, 'teacher_profile', None)
        return profile is not None and profile.programs.filter(pk=course.program_id).exists()
    return False


class TeacherAssignmentListView(TeacherRequiredMixin, View):
    template_name = 'content/teacher_assignment_list.html'

    def get(self, request, course_pk):
        course = get_object_or_404(Course, pk=course_pk)
        if not _teacher_can_manage_course(request.user, course):
            messages.error(request, 'Access denied.')
            return redirect('portal:teacher_courses')
        assignments = Assignment.objects.filter(course=course)
        return render(request, self.template_name, {'course': course, 'assignments': assignments})


class TeacherAssignmentCreateView(TeacherRequiredMixin, View):
    template_name = 'content/teacher_assignment_form.html'

    def get(self, request, course_pk):
        course = get_object_or_404(Course, pk=course_pk)
        if not _teacher_can_manage_course(request.user, course):
            messages.error(request, 'Access denied.')
            return redirect('portal:teacher_courses')
        return render(request, self.template_name, {'form': _AssignmentForm(), 'course': course, 'action': 'Create'})

    def post(self, request, course_pk):
        course = get_object_or_404(Course, pk=course_pk)
        if not _teacher_can_manage_course(request.user, course):
            messages.error(request, 'Access denied.')
            return redirect('portal:teacher_courses')
        form = _AssignmentForm(request.POST)
        if form.is_valid():
            a = form.save(commit=False)
            a.course = course
            a.created_by = request.user
            a.save()
            messages.success(request, f'Assignment "{a.title}" created.')
            return redirect('content:teacher_assignment_list', course_pk=course_pk)
        return render(request, self.template_name, {'form': form, 'course': course, 'action': 'Create'})


class TeacherAssignmentEditView(TeacherRequiredMixin, View):
    template_name = 'content/teacher_assignment_form.html'

    def get(self, request, course_pk, pk):
        course = get_object_or_404(Course, pk=course_pk)
        assignment = get_object_or_404(Assignment, pk=pk, course=course)
        if not _teacher_can_manage_course(request.user, course):
            messages.error(request, 'Access denied.')
            return redirect('portal:teacher_courses')
        return render(request, self.template_name, {'form': _AssignmentForm(instance=assignment), 'course': course, 'assignment': assignment, 'action': 'Edit'})

    def post(self, request, course_pk, pk):
        course = get_object_or_404(Course, pk=course_pk)
        assignment = get_object_or_404(Assignment, pk=pk, course=course)
        if not _teacher_can_manage_course(request.user, course):
            messages.error(request, 'Access denied.')
            return redirect('portal:teacher_courses')
        form = _AssignmentForm(request.POST, instance=assignment)
        if form.is_valid():
            form.save()
            messages.success(request, 'Assignment updated.')
            return redirect('content:teacher_assignment_list', course_pk=course_pk)
        return render(request, self.template_name, {'form': form, 'course': course, 'assignment': assignment, 'action': 'Edit'})


class TeacherSubmissionsView(TeacherRequiredMixin, View):
    template_name = 'content/teacher_submissions.html'

    def get(self, request, course_pk, pk):
        course = get_object_or_404(Course, pk=course_pk)
        assignment = get_object_or_404(Assignment, pk=pk, course=course)
        if not _teacher_can_manage_course(request.user, course):
            messages.error(request, 'Access denied.')
            return redirect('portal:teacher_courses')
        submissions = assignment.submissions.select_related('student', 'graded_by').order_by('-submitted_at')
        enrolled_count = Enrollment.objects.filter(program=course.program, is_active=True).count()
        return render(request, self.template_name, {
            'course': course,
            'assignment': assignment,
            'submissions': submissions,
            'enrolled_count': enrolled_count,
        })

    def post(self, request, course_pk, pk):
        course = get_object_or_404(Course, pk=course_pk)
        assignment = get_object_or_404(Assignment, pk=pk, course=course)
        if not _teacher_can_manage_course(request.user, course):
            messages.error(request, 'Access denied.')
            return redirect('portal:teacher_courses')

        from django.utils import timezone as tz
        valid_grades = {'A', 'B', 'C', 'D', 'F'}
        saved = 0
        for sub in assignment.submissions.all():
            field_grade = request.POST.get(f'grade_{sub.pk}', '').strip()
            field_feedback = request.POST.get(f'feedback_{sub.pk}', '').strip()
            if field_grade and field_grade in valid_grades:
                sub.grade = field_grade
                sub.feedback = field_feedback
                sub.graded_by = request.user
                sub.graded_at = tz.now()
                sub.save(update_fields=['grade', 'feedback', 'graded_by', 'graded_at'])
                saved += 1
        if saved:
            messages.success(request, f'{saved} submission{"s" if saved != 1 else ""} graded.')
        else:
            messages.info(request, 'No grades saved — select a grade for at least one submission.')
        return redirect('content:teacher_submissions', course_pk=course_pk, pk=pk)


# ---------------------------------------------------------------------------
# Assignments — Student (view list + submit)
# ---------------------------------------------------------------------------

class StudentAssignmentsView(StudentRequiredMixin, View):
    template_name = 'content/student_assignments.html'

    def get(self, request, course_pk):
        enrollment = getattr(request.user, 'enrollment', None)
        if not enrollment:
            return redirect('portal:student_dashboard')
        course = get_object_or_404(Course, pk=course_pk, program=enrollment.program, is_active=True)
        if not _student_has_access(enrollment):
            messages.warning(request, _access_denied_message(enrollment))
            return redirect('portal:student_payments')

        assignments = Assignment.objects.filter(course=course, is_published=True)
        my_submissions = {
            s.assignment_id: s
            for s in Submission.objects.filter(assignment__in=assignments, student=request.user)
        }
        rows = [{'assignment': a, 'submission': my_submissions.get(a.pk)} for a in assignments]
        return render(request, self.template_name, {'course': course, 'rows': rows, 'enrollment': enrollment})


class StudentSubmitAssignmentView(StudentRequiredMixin, View):
    template_name = 'content/student_submit_assignment.html'

    def _setup(self, request, course_pk, pk):
        enrollment = getattr(request.user, 'enrollment', None)
        if not enrollment:
            return None, None, None
        course = get_object_or_404(Course, pk=course_pk, program=enrollment.program, is_active=True)
        assignment = get_object_or_404(Assignment, pk=pk, course=course, is_published=True)
        return enrollment, course, assignment

    def get(self, request, course_pk, pk):
        enrollment, course, assignment = self._setup(request, course_pk, pk)
        if not enrollment:
            return redirect('portal:student_dashboard')
        if not _student_has_access(enrollment):
            messages.warning(request, _access_denied_message(enrollment))
            return redirect('portal:student_payments')
        existing = Submission.objects.filter(assignment=assignment, student=request.user).first()
        return render(request, self.template_name, {
            'course': course, 'assignment': assignment, 'existing': existing,
        })

    def post(self, request, course_pk, pk):
        from django.utils import timezone as tz
        enrollment, course, assignment = self._setup(request, course_pk, pk)
        if not enrollment:
            return redirect('portal:student_dashboard')
        if not _student_has_access(enrollment):
            messages.warning(request, _access_denied_message(enrollment))
            return redirect('portal:student_payments')

        notes = request.POST.get('notes', '').strip()
        file = request.FILES.get('file')

        existing = Submission.objects.filter(assignment=assignment, student=request.user).first()
        is_late = bool(assignment.due_date and tz.now() > assignment.due_date)

        if existing:
            existing.notes = notes
            existing.is_late = is_late
            if file:
                existing.file = file
            existing.submitted_at = tz.now()
            existing.save()
            messages.success(request, 'Your submission has been updated.')
        else:
            Submission.objects.create(
                assignment=assignment,
                student=request.user,
                file=file,
                notes=notes,
                is_late=is_late,
            )
            messages.success(request, 'Assignment submitted successfully.')

        return redirect('content:student_assignments', course_pk=course_pk)
