"""
Practical assessment views (Part 7): candidate submit + staff review queue.
"""
from __future__ import annotations

from django.contrib import messages
from django.core.exceptions import ValidationError
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.views import View
from django.views.generic import DetailView, ListView

from apps.courses.forms import PracticalReviewForm, PracticalSubmissionForm
from apps.courses.models import (
    PRACTICAL_APPROVED,
    PRACTICAL_NEEDS_REVISION,
    PRACTICAL_PENDING,
    PRACTICAL_REJECTED,
    CourseExamAttempt,
    PracticalSubmission,
)
from apps.courses.practical_service import (
    attempt_needs_practical,
    get_practical_for_attempt,
    review_practical,
    submit_or_update_practical,
)
from utils.permissions import AdminOrTeacherMixin, StudentRequiredMixin


class PracticalSubmitView(StudentRequiredMixin, View):
    """Candidate submits / resubmits practical after passing MCQ."""
    template_name = 'courses/practical_submit.html'

    def get_attempt(self, request, attempt_id):
        return get_object_or_404(
            CourseExamAttempt.objects.select_related('course'),
            pk=attempt_id,
            user=request.user,
            passed=True,
        )

    def get(self, request, attempt_id):
        attempt = self.get_attempt(request, attempt_id)
        if not attempt.course.requires_practical:
            messages.info(request, 'This course does not require a practical submission.')
            return redirect('courses:exam_result', attempt_id=attempt.pk)

        practical = get_practical_for_attempt(attempt)
        if practical and practical.status == PRACTICAL_APPROVED:
            messages.success(request, 'Your practical is approved. Certificate is being prepared.')
            return redirect('courses:exam_result', attempt_id=attempt.pk)
        if practical and practical.status == PRACTICAL_PENDING:
            return render(request, self.template_name, {
                'attempt': attempt,
                'course': attempt.course,
                'practical': practical,
                'form': None,
                'awaiting_review': True,
            })

        return render(request, self.template_name, {
            'attempt': attempt,
            'course': attempt.course,
            'practical': practical,
            'form': PracticalSubmissionForm(),
            'awaiting_review': False,
        })

    def post(self, request, attempt_id):
        attempt = self.get_attempt(request, attempt_id)
        if not attempt.course.requires_practical:
            return redirect('courses:exam_result', attempt_id=attempt.pk)

        form = PracticalSubmissionForm(request.POST, request.FILES)
        practical = get_practical_for_attempt(attempt)
        if not form.is_valid():
            return render(request, self.template_name, {
                'attempt': attempt,
                'course': attempt.course,
                'practical': practical,
                'form': form,
                'awaiting_review': False,
            })

        try:
            submit_or_update_practical(
                attempt=attempt,
                user=request.user,
                submission_type=form.cleaned_data['submission_type'],
                submission_url=form.cleaned_data.get('submission_url') or '',
                submission_file=form.cleaned_data.get('submission_file'),
            )
        except ValidationError as exc:
            messages.error(request, '; '.join(exc.messages) if hasattr(exc, 'messages') else str(exc))
            return render(request, self.template_name, {
                'attempt': attempt,
                'course': attempt.course,
                'practical': practical,
                'form': form,
                'awaiting_review': False,
            })

        messages.success(request, 'Practical submitted — awaiting reviewer approval.')
        return redirect('courses:practical_submit', attempt_id=attempt.pk)


class PracticalReviewQueueView(AdminOrTeacherMixin, ListView):
    """Staff queue of pending (and optionally all) practical submissions."""
    template_name = 'courses/practical_review_queue.html'
    context_object_name = 'submissions'
    paginate_by = 30

    def get_queryset(self):
        qs = PracticalSubmission.objects.select_related(
            'user', 'course', 'attempt', 'reviewed_by',
        ).order_by('status', '-submitted_at')
        status = self.request.GET.get('status', 'pending').strip()
        if status == 'all':
            return qs
        if status in {
            PRACTICAL_PENDING, PRACTICAL_APPROVED,
            PRACTICAL_NEEDS_REVISION, PRACTICAL_REJECTED,
        }:
            return qs.filter(status=status)
        return qs.filter(status=PRACTICAL_PENDING)

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)
        ctx['status_filter'] = self.request.GET.get('status', 'pending')
        ctx['pending_count'] = PracticalSubmission.objects.filter(
            status=PRACTICAL_PENDING,
        ).count()
        return ctx


class PracticalReviewDetailView(AdminOrTeacherMixin, View):
    template_name = 'courses/practical_review_detail.html'

    def get_object(self, pk):
        return get_object_or_404(
            PracticalSubmission.objects.select_related(
                'user', 'course', 'attempt', 'reviewed_by',
            ),
            pk=pk,
        )

    def get(self, request, pk):
        submission = self.get_object(pk)
        return render(request, self.template_name, {
            'submission': submission,
            'course': submission.course,
            'form': PracticalReviewForm(initial={'action': 'approve'}),
        })

    def post(self, request, pk):
        submission = self.get_object(pk)
        form = PracticalReviewForm(request.POST)
        if not form.is_valid():
            return render(request, self.template_name, {
                'submission': submission,
                'course': submission.course,
                'form': form,
            })
        try:
            review_practical(
                submission,
                reviewer=request.user,
                action=form.cleaned_data['action'],
                notes=form.cleaned_data.get('reviewer_notes') or '',
            )
        except ValidationError as exc:
            messages.error(request, '; '.join(exc.messages) if hasattr(exc, 'messages') else str(exc))
            return render(request, self.template_name, {
                'submission': submission,
                'course': submission.course,
                'form': form,
            })

        action = form.cleaned_data['action']
        if action == 'approve':
            messages.success(
                request,
                'Practical approved — certificate issuance has been queued.',
            )
        elif action == 'needs_revision':
            messages.warning(request, 'Candidate asked to resubmit with your notes.')
        else:
            messages.info(request, 'Practical rejected. Notes are visible to the candidate.')
        return redirect('courses:practical_review_queue')
