from rest_framework import generics, status, viewsets
from rest_framework.exceptions import PermissionDenied
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework_simplejwt.views import TokenObtainPairView

from .models import Permission, Role, User
from .permissions import HasPermission
from .serializers import (
    ChangePasswordSerializer,
    LoginSerializer,
    PermissionSerializer,
    RoleSerializer,
    SetApprovalPinSerializer,
    UserSerializer,
    UserWriteSerializer,
)


class LoginView(TokenObtainPairView):
    serializer_class = LoginSerializer


class ProfileView(generics.RetrieveAPIView):
    serializer_class = UserSerializer
    permission_classes = [IsAuthenticated]

    def get_object(self):
        return self.request.user


class ChangePasswordView(generics.GenericAPIView):
    serializer_class = ChangePasswordSerializer
    permission_classes = [IsAuthenticated]

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(status=status.HTTP_204_NO_CONTENT)


class SetApprovalPinView(generics.GenericAPIView):
    serializer_class = SetApprovalPinSerializer
    permission_classes = [IsAuthenticated]

    def post(self, request, *args, **kwargs):
        if not request.user.has_perm_code('sales.approve_price_overrides'):
            raise PermissionDenied('You are not permitted to set an approval PIN.')
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(status=status.HTTP_204_NO_CONTENT)


class UserViewSet(viewsets.ModelViewSet):
    """No destroy: users are referenced by past sales/purchases/expenses.
    Deactivate an account with PATCH {"is_active": false} instead."""

    date_field = 'date_joined'
    query_filters = {'role': 'role_id', 'is_active': 'is_active'}
    queryset = User.objects.all().order_by('username')
    permission_classes = [HasPermission('users.manage')]
    http_method_names = ['get', 'post', 'put', 'patch', 'head', 'options']
    ordering_fields = ('username', 'date_joined', 'role__name')
    search_fields = ('username', 'first_name', 'last_name', 'email')

    def get_serializer_class(self):
        if self.action in ('create', 'update', 'partial_update'):
            return UserWriteSerializer
        return UserSerializer


class RoleViewSet(viewsets.ModelViewSet):
    """Manager-editable roles: each is a named set of permissions users are bound to."""

    date_field = 'created_at'
    queryset = Role.objects.prefetch_related('permissions').all()
    serializer_class = RoleSerializer
    permission_classes = [HasPermission('users.manage')]
    ordering_fields = ('name', 'created_at')
    search_fields = ('name', 'description')

    def perform_destroy(self, instance):
        if instance.is_system:
            raise PermissionDenied('Built-in roles cannot be deleted.')
        if instance.users.exists():
            raise PermissionDenied('Cannot delete a role that still has users assigned to it.')
        instance.delete()


class PermissionViewSet(viewsets.ReadOnlyModelViewSet):
    """Read-only: the seeded permission catalog roles are built from."""

    queryset = Permission.objects.all()
    serializer_class = PermissionSerializer
    permission_classes = [HasPermission('users.manage')]
    pagination_class = None
    ordering_fields = ('category', 'name')
    search_fields = ('name', 'codename', 'category')
