from django.shortcuts import redirect, render
from django.views import View
from authentication.forms import UserRegistrationForm, UserLoginForm, RecoverPasswordForm, LockScreenForm
from django.http import JsonResponse, HttpResponse
from django.template.loader import render_to_string
from django.core.mail import send_mail
from django.contrib.auth.models import User
from django.contrib import auth
from django.core.mail import BadHeaderError
from django.utils.http import urlsafe_base64_encode
from django.contrib.auth.tokens import default_token_generator
from django.utils.encoding import force_bytes
from django.db.models.query_utils import Q
from django.contrib import messages
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
from settings.views import get_company_data
from users.models import *
from .forms import SetPasswordForm2
from django.views.generic.edit import FormView
from django.urls import reverse_lazy
from django.views.decorators.debug import sensitive_post_parameters
from django.views.decorators.cache import never_cache
from django.core.exceptions import ImproperlyConfigured, ValidationError
from django.http import HttpResponseRedirect, QueryDict
from django.utils.http import url_has_allowed_host_and_scheme, urlsafe_base64_decode
from django.contrib.auth import REDIRECT_FIELD_NAME, get_user_model
from django.contrib.auth import login as auth_login
from django.utils.translation import gettext_lazy as _
from django.contrib.sites.shortcuts import get_current_site

UserModel = get_user_model()


def get_current_domain(request):
    current_site = get_current_site(request)
    domain = current_site.domain
    return domain


INTERNAL_RESET_SESSION_TOKEN = "_password_reset_token"

class PasswordContextMixin:
    extra_context = None

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context.update(
            {"title": self.title, "subtitle": None, **(self.extra_context or {})}
        )
        return context
class LoginView(View):
    username = []

    def get(self, request):
        if 'username' in request.session:
            return redirect('dashboard')
        else:
            context = {'form': UserLoginForm(),"company_data":get_company_data()}
            return render(request, 'pages/authentication/auth-login.html', context)

    def post(self, request):
        username = request.POST.get('username')
        password = request.POST.get('password')

        if username and password:
            user = auth.authenticate(username=username, password=password)
            if user is not None:
                request.session['username'] = username
                auth.login(request, user)
                # Set the session expiry time to 1 minute (60 seconds)
                # request.session.set_expiry(30 * 60)
                LoginView.username.append(username)
                # data = {'success_message': 'Successfully logged in'}
                return redirect('dashboard')
                # return JsonResponse(data)
            else:
                # data = {'error_message': 'Invalid credentials'}
                # return JsonResponse(data, status=401)
                messages.error(request, "Invalid credentials" )
                return redirect('auth-login')
        else:
            messages.error(request, "Some fields are empty" )
            return redirect('auth-login')



# Recover Password
class RecoverPasswordView(View):
    template_name = 'pages/authentication/auth-recoverpw.html'

    def get(self, request):
        if 'username' in request.session:
            return redirect('dashboard')
        else:
            return render(request, self.template_name, {'form': RecoverPasswordForm,"company_data":get_company_data()})

    def post(self, request):
        if request.method == "POST":
            email = request.POST.get("email", "default value")
            if User.objects.filter(email=email).exists():
                obj = User.objects.filter(email=email).values('username')
                for i in obj:
                    user_details = {'username': i['username']}
                    username = user_details['username']
                password_reset_form = RecoverPasswordForm(request.POST)
                if password_reset_form.is_valid():
                    data = password_reset_form.cleaned_data['email']
                    associated_users = User.objects.filter(Q(email=data))
                    if associated_users.exists():
                        for user in associated_users:
                            subject = "Password Reset Requested"
                            email_template_name = "pages/authentication/email.txt"
                            c = {
                                "username": user.username,
                                "email": user.email,
                                'domain': get_current_domain(request),
                                'site_name': 'Website',
                                "uid": urlsafe_base64_encode(force_bytes(user.pk)),
                                "user": user,
                                'token': default_token_generator.make_token(user),
                                'protocol': 'http',
                                "company_data":get_company_data()
                            }
                            email = render_to_string(email_template_name, c)
                            try:
                                send_mail(subject, email, 'admin@example.com',
                                          [user.email], fail_silently=False)
                            except BadHeaderError:
                                messages.info(request, "Email Doesn't Exists ")
                                return redirect('pages-recoverpw')
                            return redirect("password_reset_done")
                password_reset_form = RecoverPasswordForm()
                return render(request=request, template_name="pages/authentication/auth-recoverpw.html", context={"password_reset_form": password_reset_form,"company_data":get_company_data()})
            else:
                if email == "":
                    messages.info(request, 'Please Enter Your Email')
                    return redirect('auth-recoverpw')
                else:
                    messages.info(request, "Email doesn't  exist")
                    return redirect('auth-recoverpw')
        else:
            return render(request, self.template_name, {'form': RecoverPasswordForm,"company_data":get_company_data()})


#  Confirm Mail
class ConfirmmailView(View):
    def get(self, request):
        return render(request, 'pages/authentication/auth-confirm-mail.html',{"company_data":get_company_data()})

#  Email Verification


class EmailVerificationView(View):
    def get(self, request):
        return render(request, 'pages/authentication/auth-email-verification.html',{"company_data":get_company_data()})

#  Two Step Verification


class TwoStepVerificationView(View):
    def get(self, request):
        return render(request, 'pages/authentication/auth-two-step-verification.html',{"company_data":get_company_data()})
    

class PasswordChangeView(View):
    def get(self, request):
        greeting = {}
        greeting['title'] ="Change Password"
        greeting['company_data'] =get_company_data()
        return render(request, 'pages/authentication/password-change.html',greeting)
    
    def post(self, request):
        if request.method == "POST":
            userid = request.user.id
            userid2 = User.objects.get(id=userid)
            
            oldpassword = request.POST.get('oldpassword')
            password = request.POST.get('newpassword1')
            password1 = request.POST.get('newpassword2')
            crt_password = UserInfo.objects.filter(user=userid2).values("password")
           
            if oldpassword and password and password1:  # Check if all fields are non-empty
                try:
                    if oldpassword == crt_password[0]['password']:
                
                        if password == password1:
                            if password != crt_password[0]['password']:
                                user = User.objects.get(id=userid)
                                user.set_password(password)
                                user.save()

                                try:
                                    userx = UserInfo.objects.get(user=userid)
                                except UserInfo.DoesNotExist:
                                    # Handle the case when UserInfo object doesn't exist
                                    userx = UserInfo.objects.create(user=userid)

                                userx.password = password
                                userx.updated_by = userid
                                userx.save()

                                # messages.success(request, "Password updated successfully.")
                                return redirect('auth-login')
                            
                            else:
                                messages.error(request, "Old password and new password should be different")
                            return redirect('change_password')
                        else:
                            messages.error(request, "New password and confirm new password do not match.")
                            return redirect('change_password')
                    else:
                            messages.error(request, "Old password does not match.")
                            return redirect('change_password')
                
                except User.DoesNotExist:
                    messages.error(request, "User not found.")
                    return redirect('change_password')
                
            else:
                messages.error(request, "Some field is empty.")
                return redirect('change_password')
        


# Lock-Screen
class LockScreenView(LoginView, View):
    def get(self, request):
        if 'username' in request.session:
            return redirect('dashboard')
        else:
            greeting = {}
            username = self.username[0]
            greeting['heading'] = username
            greeting['form'] = LockScreenForm
            greeting['company_data'] = get_company_data()
            greeting['form'] = UserLoginForm
            return render(request, 'pages/authentication/auth-login.html', greeting)

    def post(self, request):
        if request.method == "POST":
            password = request.POST['password']

            if (self.username):
                username = self.username[0]

                p_len = len(username)
                if (p_len < 6):
                    user = auth.authenticate(
                        username=username, password=password)
                    if user is not None:
                        request.session['username'] = username
                        auth.login(request, user)
                        request.session.set_expiry(1)
                        LoginView.username.append(username)
                        data = {}
                        data['success_message'] = 'Successfully unlock-screen'
                        return JsonResponse(data, safe=False)
                    else:
                        data = {}
                        data['error_message'] = 'invalid creditional'
                        return JsonResponse(data, safe=False)
                else:
                    data = {}
                    data['error_message'] = 'Password must be at least 6 characters'
                    return JsonResponse(data, safe=False)
            else:
                data = {}
                data['session_timeout'] = 'Time-out Please Login'
                return JsonResponse(data, safe=False)
        else:
            return redirect('auth-lock-screen')



class PasswordResetConfirmView2(PasswordContextMixin, FormView):
    form_class = SetPasswordForm2
    post_reset_login = False
    post_reset_login_backend = None
    reset_url_token = "set-password"
    success_url = reverse_lazy("auth-login")
    template_name = "registration/password_reset_confirm.html"
    title = _("Enter new password")
    token_generator = default_token_generator

    @method_decorator(sensitive_post_parameters())
    @method_decorator(never_cache)
    def dispatch(self, *args, **kwargs):
        if "uidb64" not in kwargs or "token" not in kwargs:
            raise ImproperlyConfigured(
                "The URL path must contain 'uidb64' and 'token' parameters."
            )

        self.validlink = False
        self.user = self.get_user(kwargs["uidb64"])

        if self.user is not None:
            token = kwargs["token"]
            if token == self.reset_url_token:
                session_token = self.request.session.get(INTERNAL_RESET_SESSION_TOKEN)
                if self.token_generator.check_token(self.user, session_token):
                    # If the token is valid, display the password reset form.
                    self.validlink = True
                    return super().dispatch(*args, **kwargs)
            else:
                if self.token_generator.check_token(self.user, token):
                    # Store the token in the session and redirect to the
                    # password reset form at a URL without the token. That
                    # avoids the possibility of leaking the token in the
                    # HTTP Referer header.
                    self.request.session[INTERNAL_RESET_SESSION_TOKEN] = token
                    redirect_url = self.request.path.replace(
                        token, self.reset_url_token
                    )
                    return HttpResponseRedirect(redirect_url)

        # Display the "Password reset unsuccessful" page.
        return self.render_to_response(self.get_context_data())

    def get_user(self, uidb64):
        try:
            # urlsafe_base64_decode() decodes to bytestring
            uid = urlsafe_base64_decode(uidb64).decode()
            user = UserModel._default_manager.get(pk=uid)
        except (
            TypeError,
            ValueError,
            OverflowError,
            UserModel.DoesNotExist,
            ValidationError,
        ):
            user = None
        return user

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs["user"] = self.user
        return kwargs

    def form_valid(self, form):
        user = form.save()
        del self.request.session[INTERNAL_RESET_SESSION_TOKEN]
        if self.post_reset_login:
            auth_login(self.request, user, self.post_reset_login_backend)
             # Add success message
        messages.success(
            self.request,
            _("Your password has been successfully changed.")
        )
        return super().form_valid(form)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        if self.validlink:
            context["validlink"] = True
        else:
            context.update(
                {
                    "form": None,
                    "title": _("Password reset unsuccessful"),
                    "validlink": False,
                }
            )
        return context
   


def logout(request):
    auth.logout(request)
    return redirect('auth-login')
    # return render(request, 'pages/authentication/auth-login.html',{"company_data":get_company_data()})
