from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode
from django.template.loader import render_to_string
from .tokens import account_activation_token
from django.core.mail import EmailMessage
from django.shortcuts import redirect
from django.core.mail import EmailMultiAlternatives
from django.conf import settings

from django.contrib.auth import login
from .models import CustomUser
from at_django_boilerplate.utils.hash_utils import hexdigest
from at_django_boilerplate.utils.encryption_utils import EncryptionUtils

def send_activation_email(request, user, to_email):
    try:
        domain = request.get_host()
        message = render_to_string('registration/verify_email_message.html', {
            'request': request,
            'user': user,
            'domain': domain,
            'uid': urlsafe_base64_encode(force_bytes(user.pk)),
            'token': account_activation_token.make_token(user),
        })

        subject = 'Welcome to we-kwick. Verify your Email'
        from_email = settings.EMAIL_HOST_USER
        _to_email = [to_email]
        text_content = ''
        html_content = message
        
        email = EmailMultiAlternatives(subject, text_content, from_email, _to_email)
        email.attach_alternative(html_content, "text/html")
        email.send()
        print(f'Sent Joining Email to {to_email} ')
        return True
    except Exception as e:
        print('Failed to Send Email')
        return False


def redirect_to_next_or_home(request):
    try:
        if 'next' in request.POST:
            _next = request.POST.get('next')
            if _next is not None:
                if _next == '' or _next == '/':
                    return redirect('home')
                else:
                    return redirect(_next)
            else:
                return redirect('home')
        else:
            return redirect('home')
    except Exception as e:
        print('Exception Post:', e)
        return redirect('home')    


def save_user(request,user_form):
    email = user_form.cleaned_data['email'].lower()
    contact_number = user_form.cleaned_data['contact_number']
    email_hash = hexdigest(email)
    existing_email = CustomUser.objects.filter(email_hash=email_hash)
    existing_email_exists = existing_email.exists()

    existing_number_exists = False
    if all([contact_number != '',contact_number != None]):
        contact_number_hash = hexdigest(contact_number)
        existing_number = CustomUser.objects.filter(contact_number_hash=contact_number_hash)
        existing_number_exists = existing_number.exists()

    if existing_email_exists:
        user_form.add_error('email', 'Email is already in use.')
    elif existing_number_exists:
        user_form.add_error('contact_number', 'Contact number is already in use.')
    else:
        try:
            user = user_form.save(commit=False)
            user.set_password(user.password)
            user.save(custom_save=True)
            login(request, user)
            user.is_active = False
            user.save()
            send_activation_email(request=request,user=user,to_email=user.get_decrypted_email())
            return True,user
        except Exception as e:
            return False,user_form

    return False,user_form



# Otp
import random
import re
from django.core.mail import send_mail
from django.core.cache import cache
from django.conf import settings

PHONE_REGEX = re.compile(r'^\+?\d{10,15}$')

def generate_otp(length=6):
    return ''.join([str(random.randint(0, 9)) for _ in range(length)])

# def send_otp(identifier, purpose='login'):
#     """
#     Sends an OTP via email or SMS based on the identifier.
#     Returns a tuple: (success: bool, method: 'email'|'sms')
#     """
#     otp = generate_otp()
#     cache_key = f'otp_{purpose}_{identifier}'
    
#     if PHONE_REGEX.match(identifier):
#         method = 'sms'
#         cache.set(cache_key, otp, timeout=300)
#         # Replace with your SMS API logic (e.g., Twilio)
#         print(f"📲 SMS OTP sent to {identifier}: {otp}")
#     else:
#         method = 'email'
#         cache.set(cache_key, otp, timeout=300)
#         try:
#             send_mail(
#                 subject=f"Your {purpose.capitalize()} OTP",
#                 message=f"Your {purpose} OTP is: {otp}\n\nThis OTP is valid for 5 minutes.",
#                 from_email=settings.EMAIL_HOST_USER,
#                 recipient_list=[identifier],
#                 fail_silently=False,
#             )
#         except Exception as e:
#             print(f"❌ Failed to send OTP email to {identifier}: {e}")
#             return False, 'email'
    
#     return True, method

from django.template.loader import render_to_string
from django.core.mail import EmailMessage

def send_otp(identifier, purpose='login'):
    """
    Sends an OTP via email or SMS based on the identifier.
    Returns a tuple: (success: bool, method: 'email'|'sms')
    """
    otp = generate_otp()
    cache_key = f'otp_{purpose}_{identifier}'

    if PHONE_REGEX.match(identifier):
        method = 'sms'
        cache.set(cache_key, otp, timeout=300)
        # Replace with your SMS API logic
        print(f"📲 SMS OTP sent to {identifier}: {otp}")
    else:
        method = 'email'
        cache.set(cache_key, otp, timeout=300)

        try:
            email_subject = f"Your {purpose.capitalize()} OTP"
            email_body = render_to_string('otp/otp_email.html', {
                'otp': otp,
                'purpose': purpose,
                'identifier': identifier,
                'validity_minutes': 5,
            })
            email = EmailMessage(
                subject=email_subject,
                body=email_body,
                from_email=settings.EMAIL_HOST_USER,
                to=[identifier],
            )
            email.content_subtype = 'html'  # Important for HTML emails
            email.send(fail_silently=False)
        except Exception as e:
            print(f"❌ Failed to send OTP email to {identifier}: {e}")
            return False, 'email'

    return True, method


def verify_otp(identifier, user_input_otp, purpose='login'):
    """
    Verifies the OTP entered by the user against the cache.
    """
    cache_key = f'otp_{purpose}_{identifier}'
    cached_otp = cache.get(cache_key)
    
    if cached_otp and cached_otp == user_input_otp:
        cache.delete(cache_key)
        return True
    return False
