# accounts/views/password_reset.py
from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth.models import User
from django.contrib.auth.tokens import default_token_generator
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.utils.encoding import force_bytes, force_str
from django.core.mail import send_mail
from django.template.loader import render_to_string
from django.utils.translation import gettext as _
from django.views.decorators.csrf import csrf_protect
from django.utils.decorators import method_decorator
from django.core.cache import cache
from rest_framework.decorators import action
from rest_framework import viewsets
from rest_framework.permissions import AllowAny
from .base import DummySerializer
from django.conf import settings


class PasswordResetViewSet(viewsets.ViewSet):
    permission_classes = (AllowAny,)
    serializer_class = DummySerializer

    @action(detail=False, methods=['GET', 'POST'], url_path='forgot-password')
    def forgot_password(self, request):
        """Handle forgot password request - send reset email"""
        base_domain = request.build_absolute_uri('/')
        
        if request.method == "POST":
            email = request.POST.get('email')
            
            if not email:
                messages.error(request, _("Please enter your email address."))
                return render(request, 'forgot_password.html', {'base_domain': base_domain})
            
            # Rate limiting - prevent email bombing
            cache_key = f'password_reset_attempts_{email}'
            attempt_count = cache.get(cache_key, 0)
            
            if attempt_count >= 3:
                messages.error(request, _("Too many reset attempts. Please try again after 1 hour."))
                return render(request, 'forgot_password.html', {'base_domain': base_domain})
            
            # Find user by email
            try:
                user = User.objects.get(email=email)
            except User.DoesNotExist:
                # Don't reveal if email exists or not for security
                messages.success(request, _("If an account exists with that email, you will receive password reset instructions."))
                return render(request, 'forgot_password.html', {'base_domain': base_domain})
            
            # Generate password reset token
            token = default_token_generator.make_token(user)
            uid = urlsafe_base64_encode(force_bytes(user.pk))
            
            # Build reset link
            reset_link = f"{base_domain}reset-password/{uid}/{token}/"
            
            # Send email
            try:
                subject = _("Password Reset Request - Not Cloud Storage")
                html_message = render_to_string('reset_password_email.html', {
                    'user': user,
                    'reset_link': reset_link,
                    'base_domain': base_domain,
                })
                plain_message = _(f"Hello {user.username},\n\nYou requested a password reset. Click the link below to reset your password:\n\n{reset_link}\n\nIf you didn't request this, please ignore this email.\n\nBest regards,\nNot Cloud Storage Team")
                
                send_mail(
                    subject,
                    plain_message,
                    settings.DEFAULT_FROM_EMAIL,
                    [email],
                    html_message=html_message,
                    fail_silently=False,
                )
                
                # Increment attempt counter
                cache.set(cache_key, attempt_count + 1, 3600)  # Expires after 1 hour
                
                messages.success(request, _("Password reset instructions have been sent to your email."))
            except Exception as e:
                messages.error(request, _("Unable to send reset email. Please try again later."))
            
            return render(request, 'forgot_password.html', {'base_domain': base_domain})
        
        return render(request, 'forgot_password.html', {'base_domain': base_domain})

    @action(detail=False, methods=['GET', 'POST'], url_path='reset-password/(?P<uidb64>[^/.]+)/(?P<token>[^/.]+)')
    def reset_password(self, request, uidb64=None, token=None):
        """Handle password reset confirmation"""
        base_domain = request.build_absolute_uri('/')
        
        try:
            uid = force_str(urlsafe_base64_decode(uidb64))
            user = User.objects.get(pk=uid)
        except (TypeError, ValueError, OverflowError, User.DoesNotExist):
            user = None
        
        # Verify token
        if user is not None and default_token_generator.check_token(user, token):
            if request.method == "POST":
                new_password = request.POST.get('new_password')
                confirm_password = request.POST.get('confirm_password')
                
                # Validate passwords
                if not new_password or not confirm_password:
                    messages.error(request, _("Please enter both new password and confirmation."))
                    return render(request, 'reset_password.html', {
                        'valid_link': True,
                        'uidb64': uidb64,
                        'token': token,
                        'base_domain': base_domain
                    })
                
                if new_password != confirm_password:
                    messages.error(request, _("Passwords do not match."))
                    return render(request, 'reset_password.html', {
                        'valid_link': True,
                        'uidb64': uidb64,
                        'token': token,
                        'base_domain': base_domain
                    })
                
                if len(new_password) < 8:
                    messages.error(request, _("Password must be at least 8 characters long."))
                    return render(request, 'reset_password.html', {
                        'valid_link': True,
                        'uidb64': uidb64,
                        'token': token,
                        'base_domain': base_domain
                    })
                
                # Check if new password is same as old
                if user.check_password(new_password):
                    messages.error(request, _("New password cannot be the same as your old password."))
                    return render(request, 'reset_password.html', {
                        'valid_link': True,
                        'uidb64': uidb64,
                        'token': token,
                        'base_domain': base_domain
                    })
                
                # Validate password strength
                from django.contrib.auth.password_validation import validate_password
                from django.core.exceptions import ValidationError
                
                try:
                    validate_password(new_password, user=user)
                except ValidationError as e:
                    for error in e.messages:
                        messages.error(request, error)
                    return render(request, 'reset_password.html', {
                        'valid_link': True,
                        'uidb64': uidb64,
                        'token': token,
                        'base_domain': base_domain
                    })
                
                # Set new password
                user.set_password(new_password)
                user.save()
                
                messages.success(request, _("Your password has been successfully reset. You can now login with your new password."))
                return redirect(f'{base_domain}login/')
            
            return render(request, 'reset_password.html', {
                'valid_link': True,
                'uidb64': uidb64,
                'token': token,
                'base_domain': base_domain
            })
        else:
            # Invalid or expired link
            return render(request, 'reset_password.html', {
                'valid_link': False,
                'base_domain': base_domain
            })