from django.db import transaction
from django.utils import timezone
from rest_framework.exceptions import PermissionDenied
from rest_framework.request import Request
from rest_framework.response import Response

from saas_base.drf.views import AuthenticatedEndpoint
from saas_base.drf.decorators import resource_permission
from saas_base.models import Invitation, Member
from saas_base.serializers.invitation import InvitationInfoSerializer

__all__ = [
    'UserInvitationListEndpoint',
    'UserInvitationAcceptEndpoint',
]


class UserInvitationListEndpoint(AuthenticatedEndpoint):
    serializer_class = InvitationInfoSerializer
    queryset = Invitation.objects.select_related('tenant', 'inviter').all()
    pagination_class = None

    def get_queryset(self):
        queryset = self.queryset.filter(email=self.request.user.email)
        return queryset.filter(status=Invitation.InviteStatus.SENT)

    @resource_permission('user.org.view')
    def get(self, request: Request, *args, **kwargs):
        """List all the current user's invitations."""
        queryset = self.filter_queryset(self.get_queryset())

        items = []
        with transaction.atomic():
            for invitation in queryset:
                if invitation.is_expired():
                    invitation.status = Invitation.InviteStatus.EXPIRED
                    invitation.save()
                else:
                    items.append(invitation)

        serializer = self.get_serializer(items, many=True)
        return Response(serializer.data)


class UserInvitationAcceptEndpoint(AuthenticatedEndpoint):
    serializer_class = InvitationInfoSerializer
    queryset = Invitation.objects.all()

    def join_tenant(self, invitation: Invitation):
        if self.request.user.email != invitation.email:
            raise PermissionDenied(' This invitation is not for you.')

        if Member.objects.filter(user=self.request.user, tenant_id=invitation.tenant_id).count():
            invitation.status = Invitation.InviteStatus.ACCEPTED
            invitation.accepted_at = timezone.now()
            invitation.save()
            return

        if invitation.is_expired():
            invitation.status = Invitation.InviteStatus.EXPIRED
            invitation.save()
            return

        with transaction.atomic():
            member = Member.objects.create(
                user=self.request.user,
                tenant_id=invitation.tenant_id,
                role=invitation.role,
            )
            member.groups.set(invitation.groups.all())
            invitation.status = Invitation.InviteStatus.ACCEPTED
            invitation.accepted_at = timezone.now()
            invitation.save()

    @resource_permission('user.org.join')
    def patch(self, request: Request, *args, **kwargs):
        status = request.data.get('status')
        obj = self.get_object()
        if status == 'accepted':
            self.join_tenant(obj)

        serializer = self.get_serializer(obj)
        return Response(serializer.data)
