"""
Views for the courses app.
"""
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from django.views import View
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib import messages
from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse_lazy, reverse
from django.core.exceptions import PermissionDenied

from apps.courses.models import Course, Module, Lesson, Category
from apps.courses.forms import CourseForm, ModuleForm, LessonForm, CategoryForm
from apps.courses.services import (
    get_published_courses, create_course, can_teacher_edit_course,
    mark_module_complete, get_completed_module_ids,
)
from utils.permissions import AdminOrTeacherMixin, TeacherRequiredMixin, AdminRequiredMixin


class CourseListView(ListView):
    """Public list of all published courses / exam tracks."""
    model = Course
    template_name = 'courses/course_list.html'
    context_object_name = 'courses'

    def get_queryset(self):
        from apps.courses.models import CATEGORY_BOTH, CATEGORY_COURSE
        qs = get_published_courses().select_related('category', 'bundle')
        cat = self.request.GET.get('category', '').strip()
        if cat:
            qs = qs.filter(category__slug=cat)
        return qs.order_by('-is_featured', 'title')

    def get_context_data(self, **kwargs):
        from apps.courses.models import CATEGORY_BOTH, CATEGORY_COURSE
        ctx = super().get_context_data(**kwargs)
        ctx['categories'] = Category.objects.filter(
            is_active=True,
            applies_to__in=[CATEGORY_COURSE, CATEGORY_BOTH],
        )
        ctx['selected_category'] = self.request.GET.get('category', '').strip()
        return ctx


class CourseDetailView(DetailView):
    """Public course detail — choose Learning Path or Direct Certification."""
    model = Course
    template_name = 'courses/course_detail.html'
    context_object_name = 'course'
    slug_url_kwarg = 'slug'

    def get_queryset(self):
        return Course.objects.filter(
            status='published', is_active=True,
        ).select_related('category').prefetch_related('teachers', 'modules__lessons')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        course = self.object
        context['modules'] = course.modules.prefetch_related('lessons').order_by('order')

        if self.request.user.is_authenticated and self.request.user.role == 'student':
            from apps.enrollments.models import Enrollment
            enrollment = Enrollment.objects.filter(
                student=self.request.user, course=course
            ).first()
            context['enrollment'] = enrollment
            progress_pct = course.get_learning_progress_percent(self.request.user)
            context['learning_progress_percent'] = progress_pct
            context['can_take_exam_learning'] = course.can_take_exam_via_learning_path(self.request.user)
            context['completed_module_ids'] = get_completed_module_ids(self.request.user, course)
        else:
            context['learning_progress_percent'] = 0
            context['can_take_exam_learning'] = False
            context['completed_module_ids'] = set()
        context['selected_path'] = self.request.GET.get('path', '').strip()
        theory_pct, practice_pct = course.get_theory_practice_ratio()
        context['theory_percent'] = theory_pct
        context['practice_percent'] = practice_pct
        context['projects'] = course.projects.filter(is_active=True).order_by('order')
        return context


class CourseLearningPathView(LoginRequiredMixin, DetailView):
    """
    Learning Path LMS shell: sidebar modules, progress bar, mark complete.
    Direct Certification Path skips this view entirely.
    """
    model = Course
    template_name = 'courses/learning_path.html'
    context_object_name = 'course'
    slug_url_kwarg = 'slug'

    def get_queryset(self):
        return Course.objects.filter(
            status='published', is_active=True, has_learning_content=True,
        ).select_related('category').prefetch_related('modules')

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)
        course = self.object
        modules = list(course.modules.order_by('order'))
        completed_ids = get_completed_module_ids(self.request.user, course)
        module_id = self.request.GET.get('module')
        current = None
        if module_id:
            current = next((m for m in modules if str(m.pk) == str(module_id)), None)
        if current is None and modules:
            current = modules[0]
        ctx['modules'] = modules
        ctx['current_module'] = current
        ctx['completed_module_ids'] = completed_ids
        ctx['progress_percent'] = course.get_learning_progress_percent(self.request.user)
        ctx['can_take_exam'] = course.can_take_exam_via_learning_path(self.request.user)
        ctx['required_percent'] = course.learning_completion_required_percent
        theory_pct, practice_pct = course.get_theory_practice_ratio()
        ctx['theory_percent'] = theory_pct
        ctx['practice_percent'] = practice_pct
        ctx['projects'] = course.projects.filter(is_active=True).order_by('order')
        ctx['mentorship_available'] = course.mentorship_available
        return ctx


class MarkModuleCompleteView(LoginRequiredMixin, View):
    """Mark a Learning Path module as complete."""

    def post(self, request, slug, module_id):
        course = get_object_or_404(
            Course, slug=slug, status='published', is_active=True, has_learning_content=True,
        )
        module = get_object_or_404(Module, pk=module_id, course=course)
        mark_module_complete(request.user, module)
        messages.success(request, f'Module "{module.title}" marked complete.')
        return redirect(
            f"{reverse('courses:learning_path', kwargs={'slug': course.slug})}?module={module.pk}"
        )

class CourseCreateView(TeacherRequiredMixin, CreateView):
    """Create a new course — teachers only."""
    model = Course
    form_class = CourseForm
    template_name = 'courses/course_form.html'

    def form_valid(self, form):
        course = create_course(form, self.request.user)
        messages.success(self.request, f"Course '{course.title}' created successfully!")
        return redirect('courses:manage_course', pk=course.pk)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['action'] = 'Create'
        return context


class CourseEditView(LoginRequiredMixin, UpdateView):
    """Edit an existing course — teacher who owns it or admin."""
    model = Course
    form_class = CourseForm
    template_name = 'courses/course_form.html'

    def dispatch(self, request, *args, **kwargs):
        course = self.get_object()
        if request.user.role == 'student':
            raise PermissionDenied
        if request.user.role == 'teacher' and not can_teacher_edit_course(request.user, course):
            messages.error(request, "You can only edit courses you are assigned to.")
            return redirect('dashboard:teacher')
        return super().dispatch(request, *args, **kwargs)

    def form_valid(self, form):
        response = super().form_valid(form)
        messages.success(self.request, "Course updated successfully!")
        return response

    def get_success_url(self):
        return reverse('courses:manage_course', kwargs={'pk': self.object.pk})

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['action'] = 'Edit'
        return context


class ManageCourseView(LoginRequiredMixin, DetailView):
    """Manage course modules and lessons."""
    model = Course
    template_name = 'courses/manage_course.html'
    context_object_name = 'course'

    def dispatch(self, request, *args, **kwargs):
        course = self.get_object()
        if request.user.role == 'student':
            raise PermissionDenied
        if request.user.role == 'teacher' and not can_teacher_edit_course(request.user, course):
            messages.error(request, "You don't have access to manage this course.")
            return redirect('dashboard:teacher')
        return super().dispatch(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['modules'] = self.object.modules.prefetch_related('lessons').order_by('order')
        return context


class ModuleCreateView(LoginRequiredMixin, CreateView):
    """Add a module to a course."""
    model = Module
    form_class = ModuleForm
    template_name = 'courses/module_form.html'

    def dispatch(self, request, *args, **kwargs):
        self.course = get_object_or_404(Course, pk=kwargs['course_pk'])
        if request.user.role == 'student':
            raise PermissionDenied
        if request.user.role == 'teacher' and not can_teacher_edit_course(request.user, self.course):
            messages.error(request, "Access denied.")
            return redirect('dashboard:teacher')
        return super().dispatch(request, *args, **kwargs)

    def form_valid(self, form):
        module = form.save(commit=False)
        module.course = self.course
        module.save()
        messages.success(self.request, f"Module '{module.title}' added!")
        return redirect('courses:manage_course', pk=self.course.pk)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['course'] = self.course
        context['action'] = 'Add Module'
        return context


class LessonCreateView(LoginRequiredMixin, CreateView):
    """Add a lesson to a module."""
    model = Lesson
    form_class = LessonForm
    template_name = 'courses/lesson_form.html'

    def dispatch(self, request, *args, **kwargs):
        self.module = get_object_or_404(Module, pk=kwargs['module_pk'])
        if request.user.role == 'student':
            raise PermissionDenied
        if request.user.role == 'teacher' and not can_teacher_edit_course(request.user, self.module.course):
            messages.error(request, "Access denied.")
            return redirect('dashboard:teacher')
        return super().dispatch(request, *args, **kwargs)

    def form_valid(self, form):
        lesson = form.save(commit=False)
        lesson.module = self.module
        lesson.save()
        messages.success(self.request, f"Lesson '{lesson.title}' added!")
        return redirect('courses:manage_course', pk=self.module.course.pk)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['module'] = self.module
        context['action'] = 'Add'
        return context


class LessonDetailView(LoginRequiredMixin, DetailView):
    """View lesson content — approved students, teacher, or admin only."""
    model = Lesson
    template_name = 'courses/lesson_detail.html'
    context_object_name = 'lesson'

    def dispatch(self, request, *args, **kwargs):
        lesson = self.get_object()
        user = request.user

        # Admins and teachers of this course always have access
        if user.role in ('admin', 'teacher'):
            return super().dispatch(request, *args, **kwargs)

        # Preview lessons are accessible to all
        if lesson.is_preview:
            return super().dispatch(request, *args, **kwargs)

        # Students need approved enrollment
        if user.role == 'student':
            from apps.enrollments.models import Enrollment
            has_access = Enrollment.objects.filter(
                student=user,
                course=lesson.module.course,
                status='approved'
            ).exists()
            if not has_access:
                messages.error(request, "You must be enrolled and approved to access this lesson.")
                return redirect('courses:course_detail', slug=lesson.module.course.slug)

        return super().dispatch(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        lesson = self.object
        context['course'] = lesson.module.course
        context['module'] = lesson.module
        # Next/prev lessons
        all_lessons = list(
            Lesson.objects.filter(module__course=lesson.module.course).order_by('module__order', 'order')
        )
        idx = next((i for i, l in enumerate(all_lessons) if l.pk == lesson.pk), None)
        context['prev_lesson'] = all_lessons[idx - 1] if idx and idx > 0 else None
        context['next_lesson'] = all_lessons[idx + 1] if idx is not None and idx < len(all_lessons) - 1 else None
        return context


class ModuleEditView(LoginRequiredMixin, UpdateView):
    """Edit an existing module — owner teacher or admin."""
    model = Module
    form_class = ModuleForm
    template_name = 'courses/module_form.html'

    def dispatch(self, request, *args, **kwargs):
        module = get_object_or_404(Module, pk=kwargs['pk'])
        self.course = module.course
        if request.user.role == 'student':
            raise PermissionDenied
        if request.user.role == 'teacher' and not can_teacher_edit_course(request.user, self.course):
            messages.error(request, "You can only manage modules for your own courses.")
            return redirect('dashboard:teacher')
        return super().dispatch(request, *args, **kwargs)

    def form_valid(self, form):
        module = form.save()
        messages.success(self.request, f"Module \u2018{module.title}\u2019 updated.")
        return redirect('courses:manage_course', pk=self.course.pk)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['course'] = self.course
        context['action'] = 'Edit Module'
        return context


class ModuleDeleteView(LoginRequiredMixin, DeleteView):
    """Delete a module and all its lessons."""
    model = Module
    template_name = 'courses/module_confirm_delete.html'

    def dispatch(self, request, *args, **kwargs):
        module = get_object_or_404(Module, pk=kwargs['pk'])
        self.course = module.course
        if request.user.role == 'student':
            raise PermissionDenied
        if request.user.role == 'teacher' and not can_teacher_edit_course(request.user, self.course):
            messages.error(request, "Access denied.")
            return redirect('dashboard:teacher')
        return super().dispatch(request, *args, **kwargs)

    def get_success_url(self):
        return reverse('courses:manage_course', kwargs={'pk': self.course.pk})

    def delete(self, request, *args, **kwargs):
        module = self.get_object()
        messages.success(request, f"Module \u2018{module.title}\u2019 deleted.")
        return super().delete(request, *args, **kwargs)


class LessonEditView(LoginRequiredMixin, UpdateView):
    """Edit an existing lesson — owner teacher or admin."""
    model = Lesson
    form_class = LessonForm
    template_name = 'courses/lesson_form.html'

    def dispatch(self, request, *args, **kwargs):
        lesson = get_object_or_404(Lesson, pk=kwargs['pk'])
        self.module_obj = lesson.module
        if request.user.role == 'student':
            raise PermissionDenied
        if request.user.role == 'teacher' and not can_teacher_edit_course(request.user, self.module_obj.course):
            messages.error(request, "Access denied.")
            return redirect('dashboard:teacher')
        return super().dispatch(request, *args, **kwargs)

    def form_valid(self, form):
        lesson = form.save()
        messages.success(self.request, f"Lesson \u2018{lesson.title}\u2019 updated.")
        return redirect('courses:manage_course', pk=self.module_obj.course.pk)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['module'] = self.module_obj
        context['action'] = 'Edit'
        return context


class LessonDeleteView(LoginRequiredMixin, DeleteView):
    """Delete a lesson."""
    model = Lesson
    template_name = 'courses/lesson_confirm_delete.html'

    def dispatch(self, request, *args, **kwargs):
        lesson = get_object_or_404(Lesson, pk=kwargs['pk'])
        self.course = lesson.module.course
        if request.user.role == 'student':
            raise PermissionDenied
        if request.user.role == 'teacher' and not can_teacher_edit_course(request.user, self.course):
            messages.error(request, "Access denied.")
            return redirect('dashboard:teacher')
        return super().dispatch(request, *args, **kwargs)

    def get_success_url(self):
        return reverse('courses:manage_course', kwargs={'pk': self.course.pk})

    def delete(self, request, *args, **kwargs):
        lesson = self.get_object()
        messages.success(request, f"Lesson \u2018{lesson.title}\u2019 deleted.")
        return super().delete(request, *args, **kwargs)


class CourseDeleteView(LoginRequiredMixin, DeleteView):
    """Delete a course — teacher who owns it or admin only."""
    model = Course
    template_name = 'courses/course_confirm_delete.html'

    def dispatch(self, request, *args, **kwargs):
        course = get_object_or_404(Course, pk=kwargs['pk'])
        if request.user.role == 'student':
            raise PermissionDenied
        if request.user.role == 'teacher' and not can_teacher_edit_course(request.user, course):
            messages.error(request, "You can only delete your own courses.")
            return redirect('dashboard:teacher')
        return super().dispatch(request, *args, **kwargs)

    def get_success_url(self):
        return reverse('dashboard:teacher_courses')

    def delete(self, request, *args, **kwargs):
        course = self.get_object()
        messages.success(request, f"Course \u2018{course.title}\u2019 deleted.")
        return super().delete(request, *args, **kwargs)
