import os
import random
import re

from django.core.files.storage import FileSystemStorage
from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string
from django.contrib.auth.views import PasswordChangeView
from django.core.mail import send_mail
from django.http import JsonResponse
from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth import get_user_model, authenticate, login, logout
from django.contrib.auth.password_validation import validate_password
from django.core.exceptions import ValidationError
from django.db import transaction
from django.utils.html import strip_tags

from core.models import SystemUser, UserAddress
from ecommerce import settings
from products.models import Category

User = get_user_model()

def validate_password(password):
    """Custom password validation"""
    if len(password) < 8:
        raise ValidationError("Password must be at least 8 characters long.")
    if not re.search(r'[A-Z]', password):
        raise ValidationError("Password must contain at least one uppercase letter.")
    if not re.search(r'[a-z]', password):
        raise ValidationError("Password must contain at least one lowercase letter.")
    if not re.search(r'\d', password):
        raise ValidationError("Password must contain at least one digit.")
    if not re.search(r'[!@#$%^&*(),.?":{}|<>]', password):
        raise ValidationError("Password must contain at least one special character.")

def registration(request):
    if request.user.is_authenticated:
        return redirect("home")

    if request.method == "POST":
        # Basic info
        first_name = request.POST.get("first_name")
        last_name = request.POST.get("last_name")
        email = request.POST.get("email")
        phone_number = request.POST.get("phone_number")
        password1 = request.POST.get("password1")
        password2 = request.POST.get("password2")
        brand_name = request.POST.get("brand_name")
        licence = request.FILES.get("licence")

        # Address info
        street_address = request.POST.get("street_address")
        city = request.POST.get("city")
        state = request.POST.get("state")
        postal_code = request.POST.get("postal_code")
        country = request.POST.get("country")

        if SystemUser.objects.filter(email=email).exists():
            messages.error(request, "Email is already registered. Please use a different one.")
            return redirect("register")

        if password1 != password2:
            messages.error(request, "Passwords do not match.")
            return redirect("register")

        try:
            validate_password(password1)
        except ValidationError as e:
            messages.error(request, e.messages[0])
            return redirect("register")

        otp = str(random.randint(100000, 999999))
        request.session["otp"] = otp
        request.session["otp_required"] = True
        request.session["user_data"] = {
            "first_name": first_name,
            "last_name": last_name,
            "email": email,
            "phone_number": phone_number,
            "password": password1,
            "brand_name": brand_name,
            "licence_name": licence.name if licence else None,
        }
        request.session["user_address"] = {
            "street_address": street_address,
            "city": city,
            "state": state,
            "postal_code": postal_code,
            "country": country,
        }

        # Save licence temporarily
        if licence:
            fs = FileSystemStorage(location=os.path.join(settings.MEDIA_ROOT, 'temp_licences'))
            filename = fs.save(licence.name, licence)
            request.session["licence_path"] = fs.path(filename)

        # Send OTP to user
        html_message = render_to_string("send-mail.html", {"otp": otp, "first_name": first_name, "last_name": last_name})
        plain_message = strip_tags(html_message)

        email_message = EmailMultiAlternatives(
            subject="Your OTP Code",
            body=plain_message,
            from_email="noreply@example.com",
            to=[email],
        )
        email_message.attach_alternative(html_message, "text/html")
        email_message.send()

        # Send admin notification to Mrwireless2018@gmail.com
        admin_body = (
            f"New user registration:\n\n"
            f"Name: {first_name} {last_name}\n"
            f"Email: {email}\n"
            f"Phone: {phone_number}\n"
            f"Brand: {brand_name}\n"
            f"Address: {street_address}, {city}, {state}, {postal_code}, {country}\n"
            f"Licence: {licence.name if licence else 'Not uploaded'}"
        )

        admin_message = EmailMultiAlternatives(
            subject="New User Registration Alert",
            body=admin_body,
            from_email="noreply@example.com",
            to=["Mrwireless2018@gmail.com"],
        )
        admin_message.send()

        messages.success(request, "An OTP has been sent to your email.")
        return redirect("verify_otp")

    categories = Category.objects.prefetch_related("subcategories__brands").all()
    category = Category.objects.prefetch_related("subcategories").all()
    return render(request, "registration.html", {'categories': categories, 'category': category})
    

def verify_otp(request):
    if not request.session.get("otp_required"):
        messages.error(request, "You are not authorized to access this page.")
        return redirect("register")

    stored_otp = request.session.get("otp")

    if request.method == "POST":
        entered_otp = request.POST.get("otp")

        print(f"Stored OTP: {stored_otp}, Entered OTP: {entered_otp}")

        if stored_otp and entered_otp and entered_otp.strip() == stored_otp.strip():
            user_data = request.session.get("user_data")
            user_address = request.session.get("user_address")

            if not user_data or not user_address:
                messages.error(request, "Session expired. Please register again.")
                return redirect("register")

            # Create user with is_active=False
            user = SystemUser.objects.create_user(
                email=user_data["email"],
                password=user_data["password"],
                first_name=user_data["first_name"],
                last_name=user_data["last_name"],
                phone_number=user_data["phone_number"],
                brand_name=user_data["brand_name"],
            )

            # Handle licence file
            if "licence_path" in request.session:
                from django.core.files import File
                licence_path = request.session["licence_path"]
                with open(licence_path, 'rb') as f:
                    user.licence.save(user_data["licence_name"], File(f))
                os.remove(licence_path)

            # Save address
            UserAddress.objects.create(
                user=user,
                street_address=user_address["street_address"],
                city=user_address["city"],
                state=user_address["state"],
                postal_code=user_address["postal_code"],
                country=user_address["country"],
                is_primary=True,
            )

            user.save()

            # Clean up session
            for key in ["otp", "otp_required", "user_data", "licence_path", "user_address"]:
                request.session.pop(key, None)

            messages.success(request, "Registration successful! Please wait for admin approval.")
            return redirect("login")
        else:
            messages.error(request, "Invalid OTP. Try again.")

    return render(request, "verify_otp.html")


def resend_otp(request):
    """Resend OTP"""
    if "user_data" not in request.session:
        messages.error(request, "Session expired. Please register again.")
        return redirect("register")

    # Generate new OTP
    new_otp = str(random.randint(100000, 999999))
    request.session["otp"] = new_otp

    # Get user details from session
    user_data = request.session["user_data"]
    email = user_data["email"]
    first_name = user_data["first_name"]
    last_name = user_data["last_name"]

    # Render the email template
    html_message = render_to_string("send-mail.html",
                                    {"otp": new_otp, "first_name": first_name, "last_name": last_name})
    plain_message = strip_tags(html_message)

    email_message = EmailMultiAlternatives(
        subject="Your New OTP Code",
        body=plain_message,
        from_email="noreply@example.com",
        to=[email],
    )
    email_message.attach_alternative(html_message, "text/html")
    email_message.send()

    messages.success(request, "A new OTP has been sent to your email.")
    return redirect("verify_otp")


def user_login(request):
    if request.user.is_authenticated:
        return redirect("home")

    if request.method == "POST":
        email = request.POST.get("email")
        password = request.POST.get("password")

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

        if user is not None:
            if user.is_active:
                login(request, user)
                messages.success(request, "Login successful!")
                return redirect("home")  # Change "home" to your actual homepage URL name
            else:
                messages.error(request, "Admin has not approved your account yet.")
        else:
            messages.error(request, "Invalid email or password. Please try again.")

    categories = Category.objects.prefetch_related("subcategories__brands").all()
    category = Category.objects.prefetch_related("subcategories").all()
    return render(request, "login.html", {'categories': categories, 'category': category})


def user_logout(request):
    logout(request)
    return redirect("login")

class CustomPasswordChangeView(PasswordChangeView):
    def form_valid(self, form):
        response = super().form_valid(form)
        return JsonResponse({"success": True, "message": "Password changed successfully!"})

    def form_invalid(self, form):
        return JsonResponse({"success": False, "errors": form.errors}, status=400)

def profile(request):
    if request.method == "POST":
        # Update SystemUser fields
        user = request.user
        user.first_name = request.POST.get('first_name', user.first_name)
        user.last_name = request.POST.get('last_name', user.last_name)
        user.phone_number = request.POST.get('phone_number', user.phone_number)
        user.brand_name = request.POST.get('brand_name', user.brand_name)

        # Handle licence file upload
        if 'licence' in request.FILES:
            licence_file = request.FILES['licence']
            fs = FileSystemStorage(location='media/licences/')
            filename = fs.save(licence_file.name, licence_file)
            user.licence = f'licences/{filename}'

        user.save()

        # Update UserProfile fields
        profile = user.profile
        profile.address = request.POST.get('address', profile.address)
        profile.date_of_birth = request.POST.get('date_of_birth', profile.date_of_birth) or None
        profile.gender = request.POST.get('gender', profile.gender) or None

        # Handle profile picture upload
        if 'profile_picture' in request.FILES:
            profile_picture = request.FILES['profile_picture']
            fs = FileSystemStorage(location='media/profile_pics/')
            filename = fs.save(profile_picture.name, profile_picture)
            profile.profile_picture = f'profile_pics/{filename}'

        profile.save()

        # Pass a flag to indicate the form was submitted
        return render(request, 'user-profile.html', {'form_submitted': True})

    return render(request, 'user-profile.html', {'form_submitted': False})

