from django.db.models import Q
from django.utils import timezone
from rest_framework import permissions,response,status,viewsets
from rest_framework.decorators import action
from rest_framework.views import APIView
from rest_framework.exceptions import PermissionDenied
from .models import *
from .serializers import *

def campus_visible(queryset,user,scope_field='campus'):
 return queryset.filter(Q(**{f'{scope_field}__isnull':True})|Q(**{scope_field:user.campus}))

class AnnouncementViewSet(viewsets.ReadOnlyModelViewSet):
 permission_classes=[permissions.IsAuthenticated]
 serializer_class=AnnouncementSerializer
 def get_queryset(self):return Announcement.objects.filter(published=True,published_at__lte=timezone.now()).filter(Q(expires_at__isnull=True)|Q(expires_at__gt=timezone.now())).filter(Q(audience='ALL')|Q(campus=self.request.user.campus))

class TopicViewSet(viewsets.ModelViewSet):
 permission_classes=[permissions.IsAuthenticated]
 serializer_class=TopicSerializer;search_fields=['title','body','author__first_name','author__last_name'];filterset_fields=['visibility','campus']
 def get_queryset(self):return ForumTopic.objects.select_related('author','author__member_profile','campus').filter(Q(visibility='GENERAL')|Q(campus=self.request.user.campus))
 def perform_create(self,s):s.save(author=self.request.user,campus=self.request.user.campus if s.validated_data.get('visibility')=='CAMPUS' else None)
 def perform_update(self,s):
  if not (self.request.user.is_staff or s.instance.author_id==self.request.user.id):raise PermissionDenied('Only the creator or an administrator can update this conversation.')
  visibility=s.validated_data.get('visibility',s.instance.visibility);s.save(campus=self.request.user.campus if visibility=='CAMPUS' else None)
 def perform_destroy(self,instance):
  if not (self.request.user.is_staff or instance.author_id==self.request.user.id):raise PermissionDenied('Only the creator or an administrator can delete this conversation.')
  instance.delete()
 @action(detail=True,methods=['get','post'])
 def replies(self,request,pk=None):
  topic=self.get_object()
  if request.method=='GET':return response.Response(ReplySerializer(topic.replies.select_related('author','author__member_profile'),many=True).data)
  if not topic.allow_replies:return response.Response({'detail':'Replies are closed for this conversation.'},status=403)
  s=ReplySerializer(data={**request.data,'topic':topic.pk});s.is_valid(raise_exception=True);s.save(author=request.user);return response.Response(s.data,status=201)

class ServiceViewSet(viewsets.ReadOnlyModelViewSet):
 permission_classes=[permissions.IsAuthenticated]
 serializer_class=ServiceSerializer;filterset_fields=['event_type'];ordering_fields=['starts_at']
 def get_queryset(self):return ServiceEvent.objects.filter(campus=self.request.user.campus).select_related('campus').prefetch_related('registrations')
 @action(detail=True,methods=['post'])
 def register(self,request,pk=None):
  event=self.get_object()
  if not event.registration_open:return response.Response({'detail':'Registration is closed.'},status=400)
  attendance,created=Attendance.objects.get_or_create(event=event,member=request.user)
  return response.Response(AttendanceSerializer(attendance).data,status=201 if created else 200)

class MyAttendanceViewSet(viewsets.ReadOnlyModelViewSet):
 permission_classes=[permissions.IsAuthenticated]
 serializer_class=AttendanceSerializer
 def get_queryset(self):return Attendance.objects.filter(member=self.request.user).select_related('event__campus')
 def list(self,request,*args,**kwargs):
  from apps.activities.models import ActivityReport
  service_rows=[{'id':f'service-{item.pk}','source':'SERVICE','title':item.event.title,'activity_type':item.event.get_event_type_display(),'date':item.event.starts_at,'venue':item.event.venue,'campus_name':item.event.campus.name,'details':item.event.description,'checked_in':item.checked_in} for item in self.get_queryset().filter(checked_in=True)]
  activity_rows=[{'id':f'activity-{item.pk}','source':'ACTIVITY','title':item.title,'activity_type':item.get_activity_type_display(),'date':item.activity_date,'venue':item.venue,'campus_name':item.campus.name if item.campus else 'National','details':item.summary,'checked_in':True} for item in ActivityReport.objects.filter(attendees=request.user).select_related('campus')]
  return response.Response(sorted(service_rows+activity_rows,key=lambda row:str(row['date']),reverse=True))

class SermonViewSet(viewsets.ReadOnlyModelViewSet):
 permission_classes=[permissions.IsAuthenticated]
 serializer_class=SermonSerializer
 def get_queryset(self):return campus_visible(Sermon.objects.filter(published=True).select_related('campus'),self.request.user)
class GalleryViewSet(viewsets.ReadOnlyModelViewSet):
 permission_classes=[permissions.IsAuthenticated]
 serializer_class=GallerySerializer
 def get_queryset(self):return campus_visible(GalleryItem.objects.filter(published=True).select_related('campus'),self.request.user)

class MemberHome(APIView):
 permission_classes=[permissions.IsAuthenticated]
 def get(self,request):
  announcements=AnnouncementViewSet();announcements.request=request
  services=ServiceEvent.objects.filter(campus=request.user.campus,starts_at__gte=timezone.now()).order_by('starts_at')[:4]
  from apps.activities.models import ActivityReport
  attendance_count=Attendance.objects.filter(member=request.user,checked_in=True).count()+ActivityReport.objects.filter(attendees=request.user).count()
  return response.Response({'announcements':AnnouncementSerializer(announcements.get_queryset()[:5],many=True).data,'services':ServiceSerializer(services,many=True,context={'request':request}).data,'sermons':SermonSerializer(campus_visible(Sermon.objects.filter(published=True),request.user)[:3],many=True).data,'gallery':GallerySerializer(campus_visible(GalleryItem.objects.filter(published=True),request.user)[:6],many=True).data,'attendance_count':attendance_count,'forum_count':ForumTopic.objects.filter(Q(visibility='GENERAL')|Q(campus=request.user.campus)).count()})
