import datetime
from decimal import Decimal
from pyexpat.errors import messages
from django.forms import ValidationError
from django.shortcuts import get_object_or_404, redirect, render , HttpResponse
from django.urls import reverse
import razorpay
from adminapp.models import AdType, Category, AdTemplate
from .models import  AdCustomization, Order, Payment, User
from django.contrib.auth import authenticate,login,logout
from django.contrib.auth.decorators import login_required
from django.contrib.auth import update_session_auth_hash
from userapp import forms
from django.contrib.auth.forms import PasswordChangeForm
from django.core.mail import send_mail
import random , math
from django.core.cache import cache
from django.conf import settings
from django.contrib import messages
from .forms import EnquiryForm, FeedbackForm, ProfileUpdateForm
from django.core.paginator import Paginator 
from datetime import datetime, timedelta
from django.utils import timezone 
from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas
import pdfkit
from django.template.loader import get_template
from django.template.loader import render_to_string
from weasyprint import HTML
import io
from django.core.validators import validate_email
import re

def loginview(request):
    if request.method == "POST":
        username = request.POST.get("username")
        password = request.POST.get("password")

        try:
            user = User.objects.get(username=username)
        except User.DoesNotExist:
            messages.error(request, "Username does not exist.")
            return render(request, "login.html")

        if not user.is_active:
            messages.error(request, "Your account has been blocked. Please contact support.")
            return render(request, "login.html")

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

        if user is not None:
            login(request, user)
            # Send login notification email
            send_mail(
                subject="Login Successful - Your Account",
                message=f"Hello {user.username},\n\nYou have successfully logged into your account.\n\nIf this wasn't you, please contact support immediately.\n\nBest Regards,\nYour AdFusion Team",
                from_email="your-email@example.com",
                recipient_list=[user.email],
                fail_silently=False,
            )
            return redirect("indexview")
        else:
            messages.error(request, "Incorrect password. Please try again.")

    return render(request, "login.html")


def logoutview(request):
    logout(request)
    return redirect(indexview)

def registerview(request):
    if request.method == "POST":
        full_name = request.POST.get('full_name', '').strip()
        phone = request.POST.get('phone', '').strip()
        username = request.POST.get('username', '').strip()
        email = request.POST.get('email', '').strip()
        password = request.POST.get('password', '')
        password1 = request.POST.get('confirm_password', '')

        # Check for empty fields
        if not all([full_name, phone, username, email, password, password1]):
            messages.error(request, "All fields are required")
            return redirect("registerview")

        # Validate email format
        try:
            validate_email(email)
        except ValidationError:
            messages.error(request, "Enter a valid email address")
            return redirect("registerview")

        # Check password match
        if password != password1:
            messages.error(request, "Passwords do not match")
            return redirect("registerview")

        # Validate password strength
        if len(password) < 8 or not re.search(r"[0-9]", password) or not re.search(r"[A-Z]", password):
            messages.error(request, "Password must be at least 8 characters long, contain a number and an uppercase letter")
            return redirect("registerview")

        # Validate phone number format (basic)
        if not re.match(r"^[6-9]\d{9}$", phone):
            messages.error(request, "Enter a valid 10-digit Indian phone number")
            return redirect("registerview")

        # Username restrictions
        if len(username) < 4 or not re.match(r"^[a-zA-Z0-9_]+$", username):
            messages.error(request, "Username must be at least 4 characters and contain only letters, numbers, or underscores")
            return redirect("registerview")

        # Check if username already exists
        if User.objects.filter(username=username).exists():
            messages.error(request, "Username already exists")
            return redirect("registerview")

        # Check if email already exists
        if User.objects.filter(email=email).exists():
            messages.error(request, "Email is already registered")
            return redirect("registerview")

        # Check if phone already exists (Assuming 'phone' field exists in User model)
        if User.objects.filter(phone=phone).exists():
            messages.error(request, "Phone number already registered")
            return redirect("registerview")

        # Create user (Assuming custom User model with 'phone' field)
        user = User.objects.create_user(
            username=username,
            email=email,
            password=password,
            first_name=full_name
        )
        user.phone = phone
        user.save()

        # Send welcome email
        send_mail(
            subject="Welcome to Our Website!",
            message=f"Hello {full_name},\n\nYour account has been successfully created!\n\nUsername: {username}\nEmail: {email}\n\nThank you for joining us.\n\nBest Regards,\nYour AdFusion Team",
            from_email="your-email@example.com",  # Replace with your sender email
            recipient_list=[email],
            fail_silently=False,
        )

        messages.success(request, "Account created successfully! Please login.")
        return redirect("loginview")

    return render(request, "register.html")

def forgetpassword(request):
    if request.method == 'POST':
        user_email = request.POST.get('email')  # Fixed typo (grt → get)
        try:
            user = User.objects.get(email=user_email)
            OTP = generate_otp()  # Generate OTP before sending it
            send_email_otp(user_email, OTP)  # Pass both email and OTP
            request.session['USER_EMAIL_SESSION'] = user_email  # Keep key consistent
            request.session['OTP_SESSION'] = OTP  # Store OTP in session
            print("Email sent successfully")
            return redirect(otppage)
        except User.DoesNotExist:  # Handle user not found error properly
            return render(request, 'forgetpassword.html', {'error': 'Email not found'})
    return render(request, 'forgetpassword.html') 

def send_email_otp(email, otp):  # Added missing otp argument
    subject = "Your Password Reset OTP"
    message = f"Hello,\n\nYour OTP for password reset is: {otp}\n\nPlease enter this OTP to reset your password. Do not share it with anyone.\n\nThank you!"
    from_email = settings.EMAIL_HOST_USER  # Fixed typo (setting → settings)
    recipient_list = [email]  # Use 'email' parameter instead of 'user_email'
    send_mail(subject, message, from_email, recipient_list)

def otppage(request):
    """Renders the OTP verification page and verifies the OTP."""
    if request.method == "POST":
        email = request.session.get("USER_EMAIL_SESSION")  # Use correct session key
        entered_otp = request.POST.get("otp")
        stored_otp = request.session.get("OTP_SESSION")  # Retrieve from session

        if stored_otp and entered_otp == stored_otp:
            del request.session["OTP_SESSION"]  # Remove OTP after verification
            request.session["otp_verified"] = True  # Store session flag
            return redirect("reset_password")  # Redirect to reset password page
        else:
            messages.error(request, "Invalid or expired OTP!")
            return redirect("otppage")
    return render(request, "otppage.html")

def generate_otp():
    digits = "0123456789"
    OTP = "".join(random.choice(digits) for _ in range(6))  # Fixed indentation & method
    print(OTP)
    return OTP

def reset_password(request):
    if not request.session.get("otp_verified"):
        messages.error(request, "Unauthorized access! Please verify OTP first.")
        return redirect("forgetpassword")
    if request.method == "POST":
        new_password = request.POST.get("password")
        confirm_password = request.POST.get("confirm_password")
        if new_password != confirm_password:
            messages.error(request, "Passwords do not match!")
            return redirect("reset_password")
        email = request.session.get("USER_EMAIL_SESSION")  # Fetch email from session
        try:
            user = User.objects.get(email=email)
        except User.DoesNotExist:
            messages.error(request, "User not found!")
            return redirect("forgetpassword")
        user.set_password(new_password)
        user.save()
        # Send confirmation email
        send_mail(
            subject="Password Reset Successful",
            message=f"Hello {user.username},\n\nYour password has been successfully changed.\n\nIf you did not request this change, please contact immediately.\n\nBest Regards,\nYour AdFusion Team",
            from_email="adfusion9@gmail.com",  # Replace with your email
            recipient_list=[email],
            fail_silently=False,
        )
        # Clear session after reset
        del request.session["otp_verified"]
        del request.session["USER_EMAIL_SESSION"]
        messages.success(request, "Password reset successful! Please login.")
        return redirect("loginview")
    return render(request, "reset_password.html")

def contactview(request):
    if request.method == "POST":
        form = EnquiryForm(request.POST)
        if form.is_valid():
            form.save()
            messages.success(request, "Your inquiry has been submitted successfully.")
            return redirect(contactview)
    else:
        form = EnquiryForm()
    return render(request, "contact.html", {"form": form})

@login_required
def submit_feedback(request):
    if request.method == "POST":
        form = FeedbackForm(request.POST)
        if form.is_valid():
            feedback = form.save(commit=False)
            feedback.user = request.user  # Assign logged-in user
            feedback.save()
            return redirect('indexview')  # Redirect to home or another page
    else:
        form = FeedbackForm()
    return render(request, 'feedback_form.html', {'form': form})

def indexview(request):
    categories = Category.objects.all()  # Fetch all categories
    templates = AdTemplate.objects.all()  # Fetch all templates
    return render(request, 'index.html', {'categories': categories, 'templates': templates})  # Pass to template

def search_results(request):
    query = request.GET.get('q')  # Get search term from query params
    results = AdTemplate.objects.filter(name__icontains=query) if query else None  # Case-insensitive search
    return render(request, 'search_results.html', {'results': results, 'query': query})

@login_required
def profile(request):
    user_orders = Order.objects.filter(user=request.user).order_by("-created_at")  # Fetch orders
    return render(request, "profile.html", {"user_orders": user_orders})

@login_required
def update_profile(request):
    if request.method == 'POST':
        form = ProfileUpdateForm(request.POST, request.FILES, instance=request.user)
        if form.is_valid():
            form.save()
            messages.success(request, "Your profile has been updated successfully.")
            return redirect('profile')  # Redirect to profile page
        else:
            messages.error(request, "Error updating your profile. Please check the form.")
    else:
        form = ProfileUpdateForm(instance=request.user)
    
    return render(request, 'update_profile.html', {'form': form})

@login_required
def change_password(request):
    if request.method == "POST":
        old_password = request.POST.get("old_password")
        new_password1 = request.POST.get("new_password1")
        new_password2 = request.POST.get("new_password2")
        if new_password1 != new_password2:
            messages.error(request, "New passwords do not match.")
        elif not request.user.check_password(old_password):
            messages.error(request, "Current password is incorrect.")
        else:
            request.user.set_password(new_password1)
            request.user.save()
            update_session_auth_hash(request, request.user)  # Keep the user logged in
            messages.success(request, "Password changed successfully!")
            return redirect("profile")  # Redirect to profile page
    return render(request, "change_password.html")

@login_required
def cancel_order(request, order_id):
    order = get_object_or_404(Order, id=order_id, user=request.user)
    if order.status == 'Completed':
        messages.error(request, "You cannot cancel a completed order.")
        return redirect('profile')  # Redirect back to the orders page
    order.status = 'Cancelled'
    order.save()
    messages.success(request, "Your order has been cancelled successfully.")
    return redirect('profile')  # Redirect back to the orders page



def category_list(request):
    categories = Category.objects.all()
    return render(request, 'category_list.html', {'categories': categories})

def category_detail(request, category_id):
    category = get_object_or_404(Category, id=category_id)
    templates = AdTemplate.objects.filter(category=category)
    return render(request, 'category_detail.html', {'category': category, 'templates': templates})

def adtemplate_list(request):
    category_id = request.GET.get("category", "")
    ad_type_id = request.GET.get("ad_type", "")
    templates = AdTemplate.objects.all()
    categories = Category.objects.all()
    ad_types = AdType.objects.all()  # Fetch all ad types
    if category_id:
        templates = templates.filter(category_id=category_id)
    if ad_type_id:
        templates = templates.filter(ad_type_id=ad_type_id)
    paginator = Paginator(templates, 8)  # Show 8 per page
    page_number = request.GET.get("page")
    templates = paginator.get_page(page_number)
    return render(request, "adtemplate_list.html",{
        "templates": templates,
        "categories": categories,
        "ad_types": ad_types,
        "selected_category": category_id,
        "selected_ad_type": ad_type_id,
    })

def adtemplate_detail(request, template_id):
    template = get_object_or_404(AdTemplate, id=template_id)
    return render(request, 'adtemplate_detail.html', {'templates': template})

@login_required()
def customize_ad(request, template_id):
    template = get_object_or_404(AdTemplate, id=template_id)
    if request.method == "POST":
        title = request.POST.get("title")
        description = request.POST.get("description")
        color = request.POST.get("color")
        style = request.POST.get("style")
        image = request.FILES.get("image", None)
        # Save and Move to Checkout
        ad = AdCustomization.objects.create(
            user=request.user,
            template=template,
            title=title,
            description=description,
            color=color,
            style=style,
            image=image,
            status="submitted"
        )
        return redirect("checkout", customize_id=ad.id)
    return render(request, "customize.html", {"template": template})



@login_required
def checkout(request, customize_id):
    customize = get_object_or_404(AdCustomization, id=customize_id)
    template = customize.template  

    base_price = Decimal(template.price)
    making_charges = base_price * Decimal("0.10")  # 10% making charge
    gst = base_price * Decimal("0.18")  # 18% GST

    additional_charge_map = {"banner": Decimal("500"), "social media": Decimal("300")}
    additional_charge = additional_charge_map.get(template.ad_type.name.lower() if template.ad_type else "", Decimal("0"))

    total_price = base_price + making_charges + gst + additional_charge

    if request.method == "POST":
        full_name = request.POST.get("full_name", "").strip() or request.user.get_full_name() or request.user.username
        email = request.POST.get("email", "").strip() or request.user.email
        phone = request.POST.get("phone", "").strip() or getattr(request.user, "phone", "")
        location_link = request.POST.get("location_link", "").strip() or None
        social_media_platform = request.POST.get("social_media_link", "").strip() or None  # Ensure this is captured
        ad_completion_date = request.POST.get("ad_completion_date", "").strip() or None

        order = Order.objects.create(
            user=request.user,
            ad=customize,
            base_price=base_price,
            making_charges=making_charges,
            gst_amount=gst,
            additional_charge=additional_charge,
            total_price=total_price,
            full_name=full_name,
            email=email,
            phone=phone,
            location_link=location_link,
            social_media_platform=social_media_platform,
            ad_completion_date=ad_completion_date,
            status="pending",  # Ensure status is set
        )

        # Create or get a Payment entry for tracking
        payment, created = Payment.objects.get_or_create(
            user=request.user,
            order=order,
            defaults={"payment_status": "pending"}
        )

        return redirect(reverse('payment', kwargs={'order_id': order.id}))

    return render(request, "order_summary.html", {
        "template": template,
        "customize": customize,
        "total_price": total_price,
        "additional_charge": additional_charge,
        "making_charges": making_charges,
        "gst": gst,
    })
    
# razorpay_client = razorpay.Client(auth=("rzp_test_5HUBK5IicnFd8q", "UllndyACZRv6mBDiEOWu4LTc"))
razorpay_client = razorpay.Client(auth=("rzp_test_kRLOHDnzOAxCT4", "BmKT1rAvCcMTFrvCkX02DSpg"))


# @login_required
# def payment(request, order_id):
#     order = get_object_or_404(Order, id=order_id, user=request.user)
#     payment, created = Payment.objects.get_or_create(order=order, user=request.user)

#     client = razorpay.Client(auth=(settings.RAZORPAY_KEY_ID, settings.RAZORPAY_KEY_SECRET))
#     razorpay_order = client.order.create({
#         "amount": int(order.total_price * 100),
#         "currency": "INR",
#         "payment_capture": "1"
#     })

#     payment.razorpay_order_id = razorpay_order["id"]
#     payment.save()

#     return render(request, "payment.html", {
#         "order": order,
#         "razorpay_key": settings.RAZORPAY_KEY_ID,
#         "razorpay_order_id": payment.razorpay_order_id,
#         "total_price": order.total_price
#     })


# @login_required
# def payment_success(request):
#     order_id = request.GET.get("order_id")
#     payment_id = request.GET.get("payment_id")

#     if not order_id or not payment_id:
#         return HttpResponse("Invalid payment details", status=400)

#     order = get_object_or_404(Order, id=order_id, user=request.user)
#     payment = Payment.objects.get(order=order)

#     payment.payment_id = payment_id  # Ensure Payment model has `payment_id`
#     payment.payment_status = "paid"
#     payment.save()

   
#     order.save()

#     return redirect(reverse("order_success", args=[order.id]))


@login_required
def payment(request, order_id):
    order = get_object_or_404(Order, id=order_id, user=request.user)
    payment, created = Payment.objects.get_or_create(order=order, user=request.user)

    amount = int(order.total_price * 100)  # in paise

    client = razorpay.Client(auth=(settings.RAZORPAY_KEY_ID, settings.RAZORPAY_KEY_SECRET))
    razorpay_order = client.order.create({
        "amount": amount,
        "currency": "INR",
        "payment_capture": "1"
    })

    payment.razorpay_order_id = razorpay_order["id"]
    payment.save()

    return render(request, "payment.html", {
        "order": order,
        "razorpay_key": settings.RAZORPAY_KEY_ID,
        "razorpay_order_id": payment.razorpay_order_id,
        "total_price": order.total_price,
        "amount": amount,
    })


@login_required
def payment_success(request):
    order_id = request.GET.get("order_id")
    payment_id = request.GET.get("payment_id")

    if not order_id or not payment_id:
        return HttpResponse("Invalid payment details", status=400)

    order = get_object_or_404(Order, id=order_id, user=request.user)
    payment = get_object_or_404(Payment, order=order)

    payment.payment_id = payment_id
    payment.payment_status = "paid"
    payment.save()

    order.status = "paid"
    order.save()

    return redirect(reverse("order_success", args=[order.id]))

@login_required
def order_success(request, order_id):
    order = get_object_or_404(Order, id=order_id, user=request.user)

    return render(request, "order_success.html", {
        "order": order,
        "order_summary": order.get_order_summary(),  # Using the `get_order_summary()` method from the model
    })

def aboutview(request):
    return render(request,'about.html')

def serviceview(request):
    return render(request,'service.html')

def projectview(request):
    return render(request,'project.html')

import io
from xhtml2pdf import pisa

# @login_required
# def generate_invoice(request, order_id):
#     order = get_object_or_404(Order, id=order_id, user=request.user)
#     output = io.BytesIO()
    
#     # Render HTML content
#     html_string = render(request, 'invoice_template.html', {'order': order}).content.decode('utf-8')

#     # Generate PDF
#     pdf_status = pisa.CreatePDF(io.StringIO(html_string), dest=output)

#     if pdf_status.err:
#         return HttpResponse('Error generating PDF', content_type='text/plain')

#     # Get the actual PDF data
#     output.seek(0)
#     response = HttpResponse(output.read(), content_type='application/pdf')
#     response['Content-Disposition'] = f'attachment; filename="invoice_{order.id}.pdf"'

#     return response

@login_required
def generate_invoice(request, order_id):
    order = get_object_or_404(Order, id=order_id, user=request.user)

    # Render the HTML with request context
    html_string = render_to_string('invoice_template.html', {'order': order, 'request': request})

    # Generate PDF
    pdf_file = io.BytesIO()
    HTML(string=html_string, base_url=request.build_absolute_uri()).write_pdf(target=pdf_file)

    # Return PDF response
    pdf_file.seek(0)
    response = HttpResponse(pdf_file.getvalue(), content_type='application/pdf')
    response['Content-Disposition'] = f'attachment; filename="invoice_{order.id}.pdf"'
    return response

