from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt
from rest_framework.parsers import JSONParser
from library.models import *
from api.serializers import *
from rest_framework import viewsets
from datetime import date, timedelta
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status, generics
from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.generics import CreateAPIView
from rest_framework.views import APIView
# from rest_framework.permissions import IsAuthenticated
from django.http import Http404
from rest_framework.pagination import PageNumberPagination
from django.db.models import F, ExpressionWrapper, fields
from rest_framework.permissions import IsAuthenticated
from rest_framework.authtoken.models import Token
from .permissions import *
from rest_framework_simplejwt.tokens import RefreshToken
from django.contrib.auth import authenticate, login, get_user_model
from django.shortcuts import get_object_or_404
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator

#set Pagination
class MyPageNumberPagination(PageNumberPagination):
    page_size = 10
    page_size_query_param = 'page_size'
    page_query_param = 'page'

#regist librarian
class LibrarianRegistrationAPIView(generics.CreateAPIView):
    queryset = CustomUser.objects.all()
    serializer_class = LibrarianRegistrationSerializer

#regist member
class MemberRegistrationAPIView(generics.ListCreateAPIView):
    queryset = CustomUser.objects.all()
    serializer_class = MemberRegistrationSerializer
#login member
class MemberLoginView(APIView):
    def post(self, request, *args, **kwargs):
        username = request.data.get('username')
        password = request.data.get('password')

        user = authenticate(username=username, password=password)

        if user is not None and user.is_member:
            refresh = RefreshToken.for_user(user)
            serializer = UserLoginSerializer(user)
            return Response({
                'refresh': str(refresh),
                'access': str(refresh.access_token),
                'user': serializer.data
            }, status=status.HTTP_200_OK)
        else:
            return Response({'detail': 'Invalid credentials'}, status=status.HTTP_401_UNAUTHORIZED)

#login librarian
class LibrarianLoginView(APIView):
    def post(self, request, *args, **kwargs):
        username = request.data.get('username')
        password = request.data.get('password')

        user = authenticate(username=username, password=password)

        if user is not None and user.is_librarian:
            refresh = RefreshToken.for_user(user)
            serializer = UserLoginSerializer(user)
            return Response({
                'refresh': str(refresh),
                'access': str(refresh.access_token),
                'user': serializer.data
            }, status=status.HTTP_200_OK)
        else:
            return Response({'detail': 'Invalid credentials'}, status=status.HTTP_401_UNAUTHORIZED)

class MemberLogoutView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            if request.user.is_librarian:
                return Response({'detail': 'invalid role user'}, status=status.HTTP_401_UNAUTHORIZED)
            # Mengambil token refresh dari request
            refresh_token = request.data["refresh"]
            
            # Memblokir token refresh
            token = RefreshToken(refresh_token)
            token.blacklist()
            
            return Response({"message": "Logout berhasil."}, status=status.HTTP_200_OK)
        except Exception as e:
            return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST)

#logout librarian
class LibrarianLogoutView(APIView):    
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            if request.user.is_member:
                return Response({'detail': 'invalid role user'}, status=status.HTTP_401_UNAUTHORIZED)
            # Mengambil token refresh dari request
            refresh_token = request.data["refresh"]
            
            # Memblokir token refresh
            token = RefreshToken(refresh_token)
            token.blacklist()
            
            return Response({"message": "Logout berhasil."}, status=status.HTTP_200_OK)
        except Exception as e:
            return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST)

#ganti password
class ChangePasswordView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request):
        serializer = ChangePasswordSerializer(data=request.data)

        if serializer.is_valid():
            # Periksa apakah password lama benar
            user = request.user
            old_password = serializer.data.get("old_password")
            if not user.check_password(old_password):
                return Response({"old_password": ["Password lama tidak sesuai."]}, status=status.HTTP_400_BAD_REQUEST)

            # Setel password baru
            new_password = serializer.data.get("new_password")
            user.set_password(new_password)
            user.save()
            return Response({"message": "Password berhasil diganti."}, status=status.HTTP_200_OK)

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class ChangeProfileView(generics.UpdateAPIView):
    permission_classes = [IsAuthenticated]
    serializer_class = UserProfileSerializer

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

#Category Create dan List
class CategoryList(generics.ListCreateAPIView):
    permission_classes = [IsAuthenticated]

    queryset = Category.objects.all()
    serializer_class = CategorySerializer

#Category Update, Detail, Delete
class CategoryDetail(generics.RetrieveUpdateDestroyAPIView):
    permission_classes = [LibrarianPermission]

    queryset = Category.objects.all()
    serializer_class = CategorySerializer

class BookListNonAuth(generics.ListCreateAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

#Book Create dan List
class BookList(generics.ListCreateAPIView):
    # permission_classes = [MemberReadOnlyPermission|LibrarianPermission]
    permission_classes = [IsAuthenticated]

    queryset = Book.objects.all()
    serializer_class = BookSerializer
    pagination_class = MyPageNumberPagination

#Book Update, Detail, Delete
class BookDetail(generics.RetrieveUpdateDestroyAPIView):
    permission_classes = [MemberReadOnlyPermission|LibrarianPermission]

    queryset = Book.objects.all()
    serializer_class = BookSerializer

#Member List
class MemberList(generics.ListCreateAPIView):
    permission_classes = [LibrarianPermission]

    queryset = Member.objects.all()
    serializer_class = MemberSerializer

#Member Update, Detail, Delete
class MemberDetail(generics.RetrieveUpdateDestroyAPIView):
    permission_classes = [LibrarianPermission]

    queryset = Member.objects.all()
    serializer_class = MemberSerializer

#Librarian List
class LibrarianList(generics.ListCreateAPIView):
    permission_classes = [LibrarianPermission]

    queryset = Librarian.objects.all()
    serializer_class = LibrarianSerializer

#Librarian Update, Detail, Delete
class LibrarianDetail(generics.RetrieveUpdateDestroyAPIView):
    permission_classes = [LibrarianPermission]

    queryset = Librarian.objects.all()
    serializer_class = LibrarianSerializer

#BookLoan Create dan List
class BookLoanList(generics.ListCreateAPIView):
    permission_classes = [IsAuthenticated, LibrarianPermission]
    

    queryset = BookLoan.objects.all().select_related('book', 'member')  # Include related objects
    serializer_class = BookLoanSerializer
    pagination_class = MyPageNumberPagination

    # def list(self, request, *args, **kwargs):
    #     book_loans = self.get_queryset()
    #     serializer = self.get_serializer(book_loans, many=True)
        
    #     # Memuat objek buku dan anggota terkait
    #     data = []
    #     for loan in serializer.data:
    #         book = Book.objects.get(id=loan['book'])
    #         member = Member.objects.get(id=loan['member'])
    #         loan['book_title'] = book.title
    #         loan['member_name'] = member.name
    #         data.append(loan)
        
    #     return Response(data)  

#BookLoan Update, Detail, Delete
class BookLoanDetail(generics.RetrieveUpdateDestroyAPIView):
    permission_classes = [IsAuthenticated, LibrarianPermission]

    queryset = BookLoan.objects.all()
    serializer_class = BookLoanSerializer

class BookSearchView(generics.ListAPIView):
    permission_classes = [MemberReadOnlyPermission|LibrarianPermission]

    serializer_class = BookSerializer

    def get_queryset(self):
        title = self.request.query_params.get('title', '')
        return Book.objects.filter(title__icontains=title)

#Book list By Year
class BookListByYear(generics.ListAPIView):
    permission_classes = [MemberReadOnlyPermission|LibrarianPermission]

    serializer_class = BookSerializer

    def get_queryset(self):
        year = self.kwargs['year']
        return Book.objects.filter(date_publish=year)
    
#Book list By Year and Category
class BookListByYearAndCategory(generics.ListAPIView):
    permission_classes = [MemberReadOnlyPermission|LibrarianPermission]

    serializer_class = BookSerializer

    def get_queryset(self):
        year = self.kwargs['year']
        category = self.kwargs['category']
        return Book.objects.filter(date_publish=year, category__name=category)

#Book list By Category
class BookListByCategory(generics.ListAPIView):
    permission_classes = [IsAuthenticated]

    serializer_class = BookSerializer

    def get_queryset(self):
        category = self.kwargs['category']
        return Book.objects.filter(category__name=category)

#Outstanding Loan List
class NearOutstandingLoansAPIView(APIView):
    permission_classes = [LibrarianPermission]

    def get(self, request, format=None):
        tomorrow = date.today() + timedelta(days=1)
        near_outstanding_loans = tomorrow + timedelta(days=2)
        near_date = BookLoan.objects.filter(due_date__gte=tomorrow, due_date__lte=near_outstanding_loans, is_returned=False)

        near_outstanding_loans = near_date.annotate(
            time_difference=ExpressionWrapper(
                F('due_date') - date.today(),
                output_field=fields.DurationField()
            )
        )

        serializer = NearOutstandingLoanSerializer(near_outstanding_loans, many=True, context={'request': request})
        return Response(serializer.data, status=status.HTTP_200_OK)

#overdue loan list
class OverdueLoansAPIView(APIView):
    permission_classes = [LibrarianPermission]
    
    def get(self, request, format=None):
        overdue_loans = BookLoan.objects.filter(due_date__lte=date.today())
        
        over_due = overdue_loans.annotate(
            dead=ExpressionWrapper(
                F('due_date') - date.today(),
                output_field=fields.DurationField()
            )
        ).exclude(is_returned=True)

        for loan in over_due:
            loan.dead = abs(loan.dead.days)

        serializer = OverdueLoanSerializer(over_due, many=True, context={'request': request})
        return Response(serializer.data, status=status.HTTP_200_OK)

# select bookloan
class LoanSelectedBook(APIView):
    permission_classes = [IsAuthenticated]

    serializer_class = MemberBookLoanSerializer

    def post(self, request):
        member = request.user.member

        # Validasi data dari permintaan menggunakan serializer
        serializer = MemberBookLoanSerializer(data=request.data)
        if serializer.is_valid():
            # Setel data yang diperlukan pada objek BookLoan
            serializer.save( member=member)

            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

# select bookloan by id    
class LoanSelectedBookById(APIView):
    permission_classes = [IsAuthenticated]

    serializer_class = MemberBookLoanByIdSerializer

    def post(self, request, id):
        # Ambil objek buku berdasarkan book_id
        book = get_object_or_404(Book, id=id)
        member = request.user.member

        # Periksa apakah buku sudah dipinjam
        if BookLoan.objects.filter(book=book, member=member, is_returned=False).exists():
            return Response({"message": "Buku sudah dipinjam."}, status=status.HTTP_400_BAD_REQUEST)

        # Validasi data dari permintaan menggunakan serializer
        serializer = MemberBookLoanByIdSerializer(data=request.data)
        if serializer.is_valid():
            # Setel data yang diperlukan pada objek BookLoan
            serializer.save(book=book, member=member)

            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    
class BookLoanViewSet(viewsets.ViewSet):
    permission_classes = [IsAuthenticated]

    def list(self, request):
        # Ambil semua objek BookLoan yang terkait dengan user (member) yang sedang login
        book_loans = BookLoan.objects.filter(member=request.user.member)

        # Serialize data BookLoan
        serializer = BookLoanMemberSerializer(book_loans, many=True, context={'request': request})

        # Kembalikan data BookLoan sebagai respons
        return Response(serializer.data)