
from django.conf import settings
from django.forms.models import BaseModelForm
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth import authenticate, login, update_session_auth_hash
from django.contrib.auth.views import LogoutView
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
# from django.contrib.auth.models import CustomUser
from datetime import date, timedelta
from django.db.models import F, ExpressionWrapper, fields
from django.urls import reverse_lazy
from .forms import *
from .models import *
from django.views.generic import *
from .mixins import LibrarianRequiredMixin
from rest_framework.pagination import PageNumberPagination
from django.contrib.auth.forms import AuthenticationForm
from django.contrib import messages
from django.contrib.auth.decorators import permission_required
from .decorators import librarian_required


#pagination
class MyPageNumberPagination(PageNumberPagination):
    page_size = 5
    page_size_query_param = 'page_size'

# Create your views here.
def homepage(request):
    return render(request, 'homepage.html')

#librarian Regist
def librarian_registration(request):
    if request.method == 'POST':
        form = LibrarianRegistrationForm(request.POST)
        if form.is_valid():
            user = form.save(commit=False)
            user.set_password(form.cleaned_data['password1'])
            user.save()
            return redirect('login')  # Redirect to librarian dashboard or another page
    else:
        form = LibrarianRegistrationForm()

    return render(request, 'librarian_registration.html', {'form': form})

#Login
def Login(request):
    if request.method == 'POST':
        form = CustomAuthenticationForm(request, data=request.POST)
        if form.is_valid():
            username = form.cleaned_data['username']
            password = form.cleaned_data['password']
            user = authenticate(request, username=username, password=password)

            if user is not None:
                login(request, user)
                return redirect('dashboard')
    else:
        form = AuthenticationForm()

    return render(request, 'login.html', {'form': form})

#member regist
def member_registration(request):
    if request.method == 'POST':
        form = MemberRegistrationForm(request.POST)
        if form.is_valid():
            user = form.save(commit=False)
            user.is_member = True
            user.save() 
            return redirect('login')  # Redirect to member dashboard or another page
    else:
        form = MemberRegistrationForm()

    return render(request, 'member_registration.html', {'form': form})

@login_required
def dashboard(request):
    return render(request, 'dashboard.html')

@librarian_required
def member_list(request):
    members = Member.objects.all()
    return render(request, 'member_list.html', {'members': members})

@librarian_required
def member_new(request):
    if request.method == 'POST':
        form = MemberForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('member_list')
    else:
        form = MemberForm()
    return render(request, 'member_new.html', {'form': form})

@librarian_required
def edit_member(request, id):
    context = {}
    member = get_object_or_404(Member, id=id)
    form = MemberForm(instance=member)
    context['member'] = member

    if request.method == 'POST':
        form = MemberForm(request.POST, instance=member)
        if form.is_valid():
            form.save()
            return redirect(member_list)
    else:
        form = MemberForm(instance=member)

    context['form'] = form
    return render(request, 'member_update.html', context)

@librarian_required
def delete_member(request, id):
    member = get_object_or_404(Member, id=id)
    member.delete()
    return redirect('member_list')

@librarian_required
def librarian_list(request):
    librarian = Librarian.objects.all()
    return render(request, 'librarian_list.html', {'librarian': librarian})

@librarian_required
def librarian_new(request):
    if request.method == 'POST':
        form = LibrarianForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('librarian_list')
    else:
        form = LibrarianForm()
    return render(request, 'librarian_new.html', {'form': form})

@librarian_required
def librarian_update(request, id):
    context = {}
    librarian = get_object_or_404(Librarian, id=id)
    form = LibrarianForm(instance=librarian)
    context['librarian'] = librarian

    if request.method == 'POST':
        form = LibrarianForm(request.POST, instance=librarian)
        if form.is_valid():
            form.save()
            return redirect(librarian_list)
    else:
        form = LibrarianForm(instance=librarian)

    context['form'] = form
    return render(request, 'librarian_update.html', context)

@librarian_required
def librarian_delete(request, pk):
    librarian = Librarian.objects.get(pk=pk)
    librarian.user.delete()
    librarian.delete()
    return redirect('librarian_list')

@librarian_required
def librarian_login_history(request):
    login_history = LoginHistory.objects.all()
    return render(request, 'librarian_login_history.html', {'login_history': login_history})

@librarian_required
def book_loan_list(request):
    book_loan = BookLoan.objects.all()
    return render(request, 'book_loan_list.html', {'book_loan': book_loan})

@librarian_required
def book_loan_new(request):
    members = Member.objects.all()
    books = Book.objects.all()
    if request.method == 'POST':
        form = BookLoanForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('book_loan_list')
    else:
        form = BookLoanForm()
    return render(request, 'book_loan_new.html', {'form': form, 'members': members, 'books': books})

@librarian_required
def book_loan_update(request, id):

    context = {}
    book_loan = get_object_or_404(BookLoan, id=id)
    form = BookLoanForm()
    context['book_loan'] = book_loan

    if request.method == 'POST':
        form = BookLoanForm(request.POST, instance=book_loan)
        if form.is_valid():
            form.save()
            return redirect('book_loan_list')
    else:
        form = BookLoanForm(instance=book_loan)
    
    context['form'] = form

    return render(request, 'book_loan_update.html', context)    

@librarian_required
def book_loan_delete(request, id):
    book_loan = get_object_or_404(BookLoan, id=id)
    book_loan.delete()
    return redirect('book_loan_list')

@librarian_required
def near_outstanding_loans(request):
    tomorow = date.today() + timedelta(days=1)
    near_outstanding_loans = tomorow + timedelta(days=2)
    near_date = BookLoan.objects.filter(due_date__gte=tomorow, 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()
        )
    )

    context = {'near_outstanding_loan': near_outstanding_loans}
               
    return render(request, 'near_outstanding_loans.html', context)

@librarian_required
def overdue_loans(request):
    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)

    context = {
        'over_due': over_due,
    }

    return render(request, 'overdue_loans.html', context)

@method_decorator(login_required, name='dispatch')
class BookList(ListView):
    model = Book
    template_name = "book_list.html"
    context_object_name = 'books'
    pagination_class = MyPageNumberPagination

@method_decorator(login_required, name='dispatch')    
class BookDetail(DetailView):
    model = Book
    template_name = 'book_detail.html'

@method_decorator(librarian_required, name='dispatch')
class BookCreateView(View):
    template_name = 'book_new.html'

    # get category list
    def get(self, request):
        category = Category.objects.all()
        return render(request, self.template_name, {'category': category})
    
    #form new book
    def post(self, request):
        form = BookForm(request.POST, request.FILES)
        form.save()
        return redirect('book-list')

@method_decorator(login_required, name='dispatch')
class BookUpdateView(LibrarianRequiredMixin, UpdateView):
    template_name = 'book_update.html'

    #get
    def get(self, request, pk):
        book = get_object_or_404(Book, pk=pk)
        category = Category.objects.all()
        return render(request, self.template_name, {'book': book, 'category': category})

    # form update book
    def post(self, request, pk):
        book = get_object_or_404(Book, pk=pk)
        form = BookForm(request.POST, request.FILES, instance=book)
        form.save()
        return redirect('book-list')

@librarian_required
def book_delete(request, id):
    book = get_object_or_404(Book, id=id)
    book.delete()
    return redirect('book-list')

@method_decorator(login_required, name='dispatch')
class BookDeleteView(LibrarianRequiredMixin, DeleteView):
    model = Book
    template_name = 'book_delete.html'
    success_url = reverse_lazy('book-list')

@method_decorator(login_required, name='dispatch')
class CategoryListView(ListView):
    model = Category
    template_name = 'category_list.html'
    context_object_name = 'categories'

@method_decorator(login_required, name='dispatch')
class CategoryCreateView(LibrarianRequiredMixin, CreateView):
    model = Category
    form_class = CategoryForm
    template_name = 'category_new.html'
    success_url = reverse_lazy('category_list')  # Adjust the success URL as needed

    def form_valid(self, form):
        form.instance.owner = self.request.user
        return super().form_valid(form)

@method_decorator(login_required, name='dispatch')
class CategoryUpdateView(LibrarianRequiredMixin,UpdateView):
    model = Category
    form_class = CategoryForm
    template_name = 'category_update.html'
    context_object_name = 'categories'
    success_url = reverse_lazy('category_list')  # Adjust the success URL as needed

    def form_valid(self, form):
        form.instance.owner = self.request.user
        return super().form_valid(form)
    
@login_required
def userchange_password(request):
    if request.method == 'POST':
        old_password = request.POST.get('old_password')
        new_password = request.POST.get('new_password')
        confirm_password = request.POST.get('confirm_password')

        # Ensure that new password and confirm password match
        if new_password != confirm_password:
            messages.error(request, 'New password and confirm password do not match.')
            return render(request, 'update_password.html')
        
        # Authenticate the user
        user = authenticate(request, username=request.user.username, password=old_password)

        if user is not None:
            # Set the new password
            user.set_password(new_password)
            user.save()
        
            update_session_auth_hash(request, user)

            messages.success(request, 'Password changed successfully.')
            return redirect('updatepassword_success')  # Redirect to the user's profile or another page
        else:
            messages.error(request, 'Incorrect old password. Please try again.')
        

    return render(request, 'update_password.html')

def updatepassword_success(request):
    return render(request, 'updatepassword_success.html')

@login_required
def update_usermember(request):
    
    if request.method == 'POST':
        form = MemberProfileUpdateForm(request.POST, instance=request.user)
        if form.is_valid():
            form.save()
            messages.success(request, 'Your Profile has been Update!')
            return redirect('updateuser_success')
    else:
        form = MemberProfileUpdateForm(instance=request.user)

    return render(request, 'update_usermember.html', {'form': form})

@login_required
def update_userlibrarian(request):
    
    if request.method == 'POST':
        form = LibrarianProfileUpdateForm(request.POST, instance=request.user)
        if form.is_valid():
            form.save()
            messages.success(request, 'Your Profile has been Update!')
            return redirect('updateuser_success')
    else:
        form = LibrarianProfileUpdateForm(instance=request.user)

    return render(request, 'update_userlibrarian.html', {'form': form})

def updateuser_success(request):
    return render(request, 'updateuser_success.html')

def unauthorized(request):
    return render(request, 'unauthorized.html')

@method_decorator(login_required, name='dispatch')
class BookLoanList(ListView):
    model = BookLoan
    template_name = 'book_loan_list.html'
    context_object_name = 'bookloan'

@method_decorator(librarian_required, name='dispatch')
class BookLoanCreateView(View):
    template_name = 'book_loan_new.html'

    # get book list
    def get(self, request):
        book = Book.objects.all()
        return render(request, self.template_name, {'book': book})
    
    # get member list
    def get(self, request):
        member = Member.objects.all()
        return render(request, self.template_name, {'member': member})
    
    #form new book
    def post(self, request):
        form = BookLoanForm(request.POST, request.FILES)
        form.save()
        return redirect('bookloan-list')
    
@method_decorator(login_required, name='dispatch')
class BookLoanUpdateView(LibrarianRequiredMixin, UpdateView):
    template_name = 'book_loan_update.html'

    #get
    def get(self, request, pk):
        bookloan = get_object_or_404(BookLoan, pk=pk)
        book = Book.objects.all()
        member = Member.objects.all()
        return render(request, self.template_name, {'bookloan': bookloan, 'book': book, 'member': member})

    # form update book
    def post(self, request, pk):
        book = get_object_or_404(Book, pk=pk)
        form = BookForm(request.POST, request.FILES, instance=book)
        form.save()
        return redirect('bookloan-update')