from django.shortcuts import render, get_object_or_404, redirect
from django.views.generic import (
    ListView, DetailView, CreateView, UpdateView, DeleteView, View, FormView
)
from django.urls import reverse_lazy, reverse
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.contrib import messages
from django.http import JsonResponse, HttpResponseForbidden, HttpResponseRedirect
from django.views.decorators.http import require_http_methods
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from django.db.models import Q
from django.utils import timezone
from django.contrib.auth import get_user_model

from .models import Task, TaskComment, TaskAttachment
from .forms import TaskForm, TaskCommentForm, TaskAttachmentForm, TaskAssignmentForm


class TaskListView(LoginRequiredMixin, ListView):
    model = Task
    template_name = 'tasks/task_list.html'
    context_object_name = 'tasks'
    paginate_by = 10
    
    def get_queryset(self):
        queryset = Task.objects.filter(
            Q(created_by=self.request.user) | Q(assigned_to=self.request.user)
        ).distinct()
        
        # Filter by status if provided
        status = self.request.GET.get('status')
        if status:
            queryset = queryset.filter(status=status)
            
        # Filter by priority if provided
        priority = self.request.GET.get('priority')
        if priority:
            queryset = queryset.filter(priority=priority)
            
        # Filter by search query if provided
        search_query = self.request.GET.get('q')
        if search_query:
            queryset = queryset.filter(
                Q(title__icontains=search_query) |
                Q(description__icontains=search_query)
            )
            
        # Order by due date (nulls last)
        queryset = queryset.order_by('-priority', 'due_date', '-created_at')
        
        return queryset
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['status_filter'] = self.request.GET.get('status', '')
        context['priority_filter'] = self.request.GET.get('priority', '')
        context['search_query'] = self.request.GET.get('q', '')
        return context


class TaskDetailView(LoginRequiredMixin, DetailView):
    model = Task
    template_name = 'tasks/task_detail.html'
    context_object_name = 'task'
    
    def get_queryset(self):
        return Task.objects.filter(
            Q(created_by=self.request.user) | Q(assigned_to=self.request.user)
        )
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['comment_form'] = TaskCommentForm()
        context['attachment_form'] = TaskAttachmentForm()
        return context


class TaskCreateView(LoginRequiredMixin, CreateView):
    model = Task
    form_class = TaskForm
    template_name = 'tasks/task_form.html'
    
    def form_valid(self, form):
        form.instance.created_by = self.request.user
        response = super().form_valid(form)
        messages.success(self.request, 'Task created successfully!')
        return response
    
    def get_success_url(self):
        return reverse('tasks:task-detail', kwargs={'pk': self.object.pk})
    
    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['user'] = self.request.user
        return kwargs


class TaskUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
    model = Task
    form_class = TaskForm
    template_name = 'tasks/task_form.html'
    
    def test_func(self):
        task = self.get_object()
        return self.request.user == task.created_by or self.request.user == task.assigned_to
    
    def form_valid(self, form):
        response = super().form_valid(form)
        messages.success(self.request, 'Task updated successfully!')
        return response
    
    def get_success_url(self):
        return reverse('tasks:task-detail', kwargs={'pk': self.object.pk})
    
    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['user'] = self.request.user
        return kwargs


class TaskDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
    model = Task
    template_name = 'tasks/task_confirm_delete.html'
    success_url = reverse_lazy('tasks:task-list')
    
    def test_func(self):
        task = self.get_object()
        return self.request.user == task.created_by
    
    def delete(self, request, *args, **kwargs):
        response = super().delete(request, *args, **kwargs)
        messages.success(request, 'Task deleted successfully!')
        return response


@method_decorator(csrf_exempt, name='dispatch')
class TaskCompleteView(LoginRequiredMixin, View):
    def post(self, request, *args, **kwargs):
        task = get_object_or_404(Task, pk=kwargs['pk'])
        
        # Check if user has permission to complete the task
        if request.user != task.created_by and request.user != task.assigned_to:
            return HttpResponseForbidden("You don't have permission to complete this task.")
        
        # Toggle task completion
        if task.status == 'done':
            task.status = 'todo'
            task.completed_at = None
            message = 'Task marked as incomplete.'
        else:
            task.status = 'done'
            task.completed_at = timezone.now()
            message = 'Task marked as complete!'
        
        task.save()
        
        if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
            return JsonResponse({
                'status': 'success',
                'message': message,
                'task_status': task.status,
                'completed_at': task.completed_at.strftime('%b %d, %Y %I:%M %p') if task.completed_at else None
            })
        
        messages.success(request, message)
        return redirect('tasks:task-detail', pk=task.pk)


def add_comment(request, pk):
    task = get_object_or_404(Task, pk=pk)
    
    if request.method == 'POST':
        form = TaskCommentForm(request.POST)
        if form.is_valid():
            comment = form.save(commit=False)
            comment.task = task
            comment.author = request.user
            comment.save()
            messages.success(request, 'Comment added successfully!')
    
    return redirect('tasks:task-detail', pk=task.pk)


def delete_comment(request, pk):
    comment = get_object_or_404(TaskComment, pk=pk)
    
    # Check if user has permission to delete the comment
    if request.user != comment.author and not request.user.is_staff:
        return HttpResponseForbidden("You don't have permission to delete this comment.")
    
    task_pk = comment.task.pk
    comment.delete()
    messages.success(request, 'Comment deleted successfully!')
    
    return redirect('tasks:task-detail', pk=task_pk)


def upload_attachment(request, pk):
    task = get_object_or_404(Task, pk=pk)
    
    if request.method == 'POST':
        form = TaskAttachmentForm(request.POST, request.FILES)
        if form.is_valid():
            attachment = form.save(commit=False)
            attachment.task = task
            attachment.uploaded_by = request.user
            attachment.save()
            messages.success(request, 'File uploaded successfully!')
    
    return redirect('tasks:task-detail', pk=task.pk)


def delete_attachment(request, pk):
    attachment = get_object_or_404(TaskAttachment, pk=pk)
    
    # Check if user has permission to delete the attachment
    if request.user != attachment.uploaded_by and not request.user.is_staff:
        return HttpResponseForbidden("You don't have permission to delete this attachment.")
    
    task_pk = attachment.task.pk
    attachment.file.delete()  # Delete the file from storage
    attachment.delete()  # Delete the database record
    
    messages.success(request, 'Attachment deleted successfully!')
    return redirect('tasks:task-detail', pk=task_pk)


class TaskApprovalView(LoginRequiredMixin, UserPassesTestMixin, View):
    """View for approving or rejecting tasks"""
    
    def test_func(self):
        # Only allow users with president role to approve/reject tasks
        return hasattr(self.request.user, 'role') and self.request.user.role.name == 'president'
    
    def post(self, request, pk, action):
        task = get_object_or_404(Task, pk=pk)
        
        if action == 'approve':
            task.approval_status = 'approved'
            task.approved_by = request.user
            task.approved_at = timezone.now()
            task.rejection_reason = None
            message = 'Task has been approved successfully.'
        elif action == 'reject':
            task.approval_status = 'rejected'
            task.approved_by = request.user
            task.approved_at = timezone.now()
            task.rejection_reason = request.POST.get('rejection_reason', 'No reason provided')
            message = 'Task has been rejected.'
        else:
            return JsonResponse({'status': 'error', 'message': 'Invalid action'}, status=400)
        
        task.save()
        
        if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
            return JsonResponse({
                'status': 'success',
                'message': message,
                'approval_status': task.get_approval_status_display(),
                'approved_by': task.approved_by.get_full_name() if task.approved_by else None,
                'approved_at': task.approved_at.strftime('%Y-%m-%d %H:%M') if task.approved_at else None
            })
        
        messages.success(request, message)
        return redirect('president-dashboard')


def get_tasks_awaiting_approval(user):
    """Helper function to get tasks awaiting approval"""
    if hasattr(user, 'role') and user.role.name == 'president':
        return Task.objects.filter(
            Q(approval_status='pending') | 
            Q(priority='high') | 
            Q(scope='national')
        ).exclude(approval_status='approved').distinct()
    return Task.objects.none()


class TaskAssignmentView(LoginRequiredMixin, View):
    """View for assigning tasks to users."""
    
    def post(self, request, *args, **kwargs):
        form = TaskAssignmentForm(request.POST, user=request.user)
        
        if form.is_valid():
            task_id = form.cleaned_data['task_id']
            assigned_to = form.cleaned_data['assigned_to']
            
            try:
                task = Task.objects.get(id=task_id)
                
                # Check if user has permission to assign this task
                if task.created_by != request.user and not request.user.is_superuser:
                    return JsonResponse({
                        'success': False,
                        'message': 'You do not have permission to assign this task.'
                    }, status=403)
                
                # Update task assignment
                task.assigned_to = assigned_to
                task.status = 'in_progress'
                task.updated_by = request.user
                task.save()
                
                # Create a system note about the assignment
                TaskComment.objects.create(
                    task=task,
                    author=request.user,
                    comment=f'Task assigned to {assigned_to.get_full_name() or assigned_to.email} by {request.user.get_full_name() or request.user.email}',
                    is_system_note=True
                )
                
                # Prepare success response
                response_data = {
                    'success': True,
                    'message': f'Task "{task.title}" has been assigned to {assigned_to.get_full_name() or assigned_to.email}.'
                }
                
                return JsonResponse(response_data)
                
            except Task.DoesNotExist:
                return JsonResponse({
                    'success': False,
                    'message': 'The specified task does not exist.'
                }, status=404)
                
        # Form is invalid
        return JsonResponse({
            'success': False,
            'message': 'Invalid form data. Please check your input.',
            'errors': form.errors
        }, status=400)
    
    def get(self, request, *args, **kwargs):
        # Handle GET requests (for modal form)
        form = TaskAssignmentForm(user=request.user)
        return render(request, 'tasks/task_assign.html', {'form': form})


# API Views
from rest_framework import generics, permissions
from .serializers import TaskSerializer

class TaskListAPIView(generics.ListCreateAPIView):
    serializer_class = TaskSerializer
    permission_classes = [permissions.IsAuthenticated]
    
    def get_queryset(self):
        return Task.objects.filter(
            Q(created_by=self.request.user) | Q(assigned_to=self.request.user)
        ).distinct()
    
    def perform_create(self, serializer):
        serializer.save(created_by=self.request.user)


class TaskDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
    serializer_class = TaskSerializer
    permission_classes = [permissions.IsAuthenticated]
    
    def get_queryset(self):
        return Task.objects.filter(
            Q(created_by=self.request.user) | Q(assigned_to=self.request.user)
        )


class TaskStatusUpdateAPIView(generics.UpdateAPIView):
    """
    API endpoint to update task status.
    Expected payload: {"status": "in_progress" | "completed" | "pending" | "delayed"}
    """
    serializer_class = TaskSerializer
    permission_classes = [permissions.IsAuthenticated]
    http_method_names = ['patch']
    
    def get_queryset(self):
        # Only allow updating tasks assigned to the current user
        return Task.objects.filter(assigned_to=self.request.user)
    
    def patch(self, request, *args, **kwargs):
        task = self.get_object()
        new_status = request.data.get('status')
        
        if not new_status:
            return Response(
                {'error': 'Status is required'}, 
                status=status.HTTP_400_BAD_REQUEST
            )
        
        # Validate status transition
        valid_statuses = dict(Task.STATUS_CHOICES).keys()
        if new_status not in valid_statuses:
            return Response(
                {'error': f'Invalid status. Must be one of: {", ".join(valid_statuses)}'}, 
                status=status.HTTP_400_BAD_REQUEST
            )
        
        # Update task status
        task.status = new_status
        
        # If marking as completed, set completed_at
        if new_status == 'completed':
            task.completed_at = timezone.now()
        
        task.save()
        
        # Log the status change
        TaskComment.objects.create(
            task=task,
            user=request.user,
            comment=f'Status changed to {task.get_status_display()}',
            is_system=True
        )
        
        serializer = self.get_serializer(task)
        return Response(serializer.data)
