from django.views.decorators.http import require_POST
from cargo.models import Sender, Receiver, Address
from home.models import CompanyProfile
from django.http import JsonResponse
from django.forms import inlineformset_factory
from .forms import InvoiceItemsForm
from django.utils.timezone import now
import os
import json
import openpyxl
from datetime import datetime
from django.contrib import messages
from django.contrib.auth import authenticate, login
from django.contrib.auth.decorators import login_required, permission_required
from django.contrib.auth.models import User
from django.core.exceptions import (
    PermissionDenied, ValidationError, FieldDoesNotExist
)
from django.core.mail import send_mail
from django.core.paginator import Paginator
from django.core.validators import validate_email
from django.db.models import (
    Q, Count, ProtectedError
)
from django.http import HttpResponse, JsonResponse
from django.shortcuts import (
    render, redirect, get_object_or_404, get_list_or_404
)
from django.template.loader import get_template
from django.urls import reverse
from django.utils.html import escape
from django.utils.text import slugify
from django.views.decorators.csrf import csrf_exempt

from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
from cargo.models import AddExpense, Invoice, InvoiceItems, Item
# Models
from .models import (
    Product, Category, Cart, CartItem, Slide, FAQ,
    FAQAnswer, AnswerComment, NewsletterSubscriber,
    Order, OrderItem, Review, Blog, Wishlist, Testimonial
)

# Forms
from .forms import (
    ProfileUpdateForm, FAQForm, FAQAnswerForm,
    ReviewReplyForm, UserUpdateForm, ReviewForm, InvoiceForm
)


def generic_invoice_view(
    request,
    model,
    pk,
    template_name,
    context_name='object',
    permission=None,
):
    # Dynamically build permission if not provided
    if permission is None:
        permission = f"{model._meta.app_label}.view_{model._meta.model_name}"

    if not request.user.has_perm(permission):
        raise PermissionDenied

    obj = get_object_or_404(model, pk=pk)

    return render(request, template_name, {
        context_name: obj,
        'model_verbose_name': model._meta.verbose_name.title(),
    })


def export_to_pdf_view(
    request,
    model,
    fields,
    filename_prefix='export',
    selected_only=False,
    permission=None,
    redirect_url_name='admin_page'
):
    # 🔐 Permission check
    if permission is None:
        app_label = model._meta.app_label
        model_name = model._meta.model_name
        permission = f'{app_label}.view_{model_name}'

    if not request.user.has_perm(permission):
        messages.error(
            request, "You do not have permission to perform this action.")
        return redirect(redirect_url_name)

    queryset = model.objects.all()

    # 🔍 Search filter (optional)
    query = request.GET.get('q')
    if query:
        filters = Q()
        for field in fields:
            filters |= Q(**{f"{field}__icontains": query})
        queryset = queryset.filter(filters)

    # ✅ Export selected only
    if selected_only and request.method == 'POST':
        selected_ids = request.POST.getlist('selected_ids')
        if selected_ids:
            queryset = queryset.filter(id__in=selected_ids)

    # 🧾 Setup PDF
    response = HttpResponse(content_type='application/pdf')
    filename = f"{slugify(filename_prefix)}.pdf"
    response['Content-Disposition'] = f'attachment; filename=\"{filename}\"'

    p = canvas.Canvas(response, pagesize=A4)
    width, height = A4

    # 📌 Header
    title_text = filename_prefix.replace('_', ' ').title()
    generated_at = datetime.now().strftime("%Y-%m-%d %H:%M")

    p.setFont("Helvetica-Bold", 16)
    p.drawString(50, height - 50, "📦 Nana Tradings")

    p.setFont("Helvetica", 10)
    p.drawRightString(width - 50, height - 45, f"Generated: {generated_at}")

    p.setFont("Helvetica-Bold", 13)
    p.drawString(50, height - 70, title_text)

    # 📊 Table Layout
    y = height - 100
    left_margin = 50
    right_margin = 50
    usable_width = width - left_margin - right_margin
    col_width = usable_width / len(fields)

    # Table Header
    p.setFont("Helvetica-Bold", 10)
    for i, field in enumerate(fields):
        p.drawString(left_margin + i * col_width, y, field.title())

    # Table Rows
    p.setFont("Helvetica", 10)
    for obj in queryset:
        y -= 20
        if y < 50:
            p.showPage()
            y = height - 50
            # Redraw header on new page
            p.setFont("Helvetica-Bold", 10)
            for i, field in enumerate(fields):
                p.drawString(left_margin + i * col_width, y, field.title())
            y -= 20
            p.setFont("Helvetica", 10)

        for i, field in enumerate(fields):
            value = str(getattr(obj, field))
            p.drawString(left_margin + i * col_width, y, value)

    p.showPage()
    p.save()
    return response


def export_to_excel_view(
    request,
    model,
    fields,
    filename_prefix='export',
    selected_only=False,
    permission=None,
    redirect_url_name='admin_page'
):
    # 🔐 Permission check
    if permission is None:
        app_label = model._meta.app_label
        model_name = model._meta.model_name
        permission = f'{app_label}.view_{model_name}'

    if not request.user.has_perm(permission):
        messages.error(
            request, "You do not have permission to perform this action.")
        return redirect(redirect_url_name)

    queryset = model.objects.all()

    # 🔍 Optional: Search filter
    query = request.GET.get('q')
    if query:
        filters = Q()
        for field in fields:
            filters |= Q(**{f"{field}__icontains": query})
        queryset = queryset.filter(filters)

    # ✅ Export only selected items if applicable
    if selected_only and request.method == 'POST':
        selected_ids = request.POST.getlist('selected_ids')
        if selected_ids:
            queryset = queryset.filter(id__in=selected_ids)

    # 📊 Create Excel workbook
    wb = openpyxl.Workbook()
    ws = wb.active
    ws.title = "Data"

    # Header row
    ws.append([field.replace('_', ' ').title() for field in fields])

    # Data rows (convert all values to string)
    for obj in queryset:
        row = [str(getattr(obj, field)) for field in fields]
        ws.append(row)

    # 📥 Return response
    response = HttpResponse(
        content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
    )
    filename = f"{slugify(filename_prefix)}.xlsx"
    response['Content-Disposition'] = f'attachment; filename=\"{filename}\"'
    wb.save(response)
    return response


def generic_list_view(
    request,
    model,
    template_name,
    context_name,
    search_fields=None,
    items_per_page=10,
    permission=None,
    redirect_url_name='home',
    extra_filters=None  # 👈 NEW: optional dict
):
    # 🔐 Permission check
    if permission is None:
        app_label = model._meta.app_label
        model_name = model._meta.model_name
        permission = f'{app_label}.view_{model_name}'

    if not request.user.has_perm(permission):
        messages.error(
            request, "You do not have permission to access this page.")
        return redirect(redirect_url_name)

    queryset = model.objects.all()
    query = request.GET.get('q', '')

    if query and search_fields:
        filters = Q()
        for field in search_fields:
            filters |= Q(**{f"{field}__icontains": query})
        queryset = queryset.filter(filters)

    sort = request.GET.get('sort', 'newest')
    try:
        model._meta.get_field('created_at')
        if sort == 'oldest':
            queryset = queryset.order_by('created_at')
        else:
            queryset = queryset.order_by('-created_at')
    except FieldDoesNotExist:
        # Don't apply ordering if the model doesn't have 'created_at'
        pass

    # ✅ Apply extra filters like status
    if extra_filters:
        for key, field in extra_filters.items():
            value = request.GET.get(key)
            if value:
                queryset = queryset.filter(**{field: value})

    paginator = Paginator(queryset, items_per_page)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)

    return render(request, template_name, {
        context_name: page_obj,
        'search_query': query,
        'model_verbose_name': model._meta.verbose_name.title(),
        'sort': sort,
    })


def generic_form_view(
    request,
    model,
    form_class,
    template_name,
    success_url,
    title,
    object_instance=None,
    object_name_field='name',
    permission=None
):
    instance = object_instance

    # 🔐 Dynamic permission detection
    if permission is None:
        app_label = model._meta.app_label
        model_name = model._meta.model_name
        action = 'change' if instance else 'add'
        permission = f"{app_label}.{action}_{model_name}"

    if not request.user.has_perm(permission):
        raise PermissionDenied

    # ✅ Handle file uploads correctly
    form = form_class(request.POST or None,
                      request.FILES or None, instance=instance)

    if form.is_valid():
        obj = form.save()
        action = "updated" if instance else "created"
        label = getattr(obj, object_name_field, str(obj))
        model_verbose = model._meta.verbose_name.title()
        messages.success(
            request,
            f'{model_verbose} "<strong>{escape(label)}</strong>" {action} successfully.'
        )
        return redirect(success_url)

    return render(request, template_name, {
        'form': form,
        'title': title
    })


def generic_delete_view(
    request,
    model,
    pk,
    success_url,
    template_name,
    object_name_field='name',
    context_name='object',
    permission=None
):
    obj = get_object_or_404(model, pk=pk)
    object_label = getattr(obj, object_name_field, str(obj))
    model_name = model._meta.verbose_name.title()

    # 🔐 Permission check (dynamically determined if not passed)
    if permission is None:
        app_label = model._meta.app_label
        model_name_lower = model._meta.model_name
        permission = f"{app_label}.delete_{model_name_lower}"

    if not request.user.has_perm(permission):
        raise PermissionDenied

    related_items = []

    if request.method == 'POST':
        try:
            obj.delete()
            messages.error(
                request,
                f'{model_name} "<strong>{escape(object_label)}</strong>" deleted successfully.'
            )
            return redirect(success_url)
        except ProtectedError as e:
            for related in e.protected_objects:
                related_items.append({
                    'model': related._meta.verbose_name.title(),
                    'name': str(related)
                })
            messages.error(
                request,
                f'Cannot delete "<strong>{escape(object_label)}</strong>" because it is linked to other items.'
            )

    return render(request, template_name, {
        context_name: obj,
        'object': obj,
        'related_items': related_items,
        'model_verbose_name': model_name,
    })


def bulk_delete_view(request, model, template_name, success_url, object_name_field='name', permission=None):
    if request.method != 'POST':
        messages.warning(request, "Invalid request method.")
        return redirect(success_url)

    ids = request.POST.getlist('selected_ids')

    if not ids:
        messages.warning(request, "No items selected.")
        return redirect(success_url)

    # 🔐 Permission check
    if permission is None:
        app_label = model._meta.app_label
        model_name = model._meta.model_name
        # fallback to model-level delete permission
        permission = f'{app_label}.delete_{model_name}'

    if not request.user.has_perm(permission):
        raise PermissionDenied

    objects = get_list_or_404(model, id__in=ids)

    if 'confirm' in request.POST:
        try:
            count = len(objects)
            model.objects.filter(id__in=ids).delete()
            messages.success(request, f'{count} item(s) deleted successfully.')
            return redirect(success_url)
        except ProtectedError as e:
            protected_objects = list(e.protected_objects)[:5]
            related_info = ", ".join(
                f"{obj._meta.verbose_name.title()}: <strong>{escape(str(obj))}</strong>"
                for obj in protected_objects
            )
            messages.error(
                request,
                f'Cannot delete item(s) because they are linked to: {related_info}'
                + ("..." if len(e.protected_objects) > 5 else "")
            )
            return redirect(success_url)

    return render(request, template_name, {
        'objects': objects,
        'model_verbose_name': model._meta.verbose_name.title(),
        'object_name_field': object_name_field,
    })


def bulk_status_update_view(
    request,
    model,
    success_url,
    field_name='status',
    valid_choices=None,
    permission=None
):
    if request.method == 'POST':
        ids = request.POST.getlist('selected_ids')
        new_status = request.POST.get('bulk_status')

        # 🔐 Permission check
        if permission is None:
            app_label = model._meta.app_label
            model_name = model._meta.model_name
            # fallback to standard change permission
            permission = f'{app_label}.change_{model_name}'

        if not request.user.has_perm(permission):
            raise PermissionDenied

        if ids and new_status and (valid_choices is None or new_status in dict(valid_choices)):
            model.objects.filter(id__in=ids).update(**{field_name: new_status})
            messages.success(
                request,
                f"{len(ids)} item(s) updated to status: {new_status.capitalize()}"
            )
        else:
            messages.warning(request, "Invalid selection or status.")

    return redirect(success_url)


InvoiceItemFormSet = inlineformset_factory(
    Invoice,
    InvoiceItems,
    form=InvoiceItemsForm,
    extra=0,
    can_delete=True
)


def invoice_create_or_update_view(request, pk=None):
    instance = get_object_or_404(Invoice, pk=pk) if pk else None
    permission = f'cargo.{"change" if instance else "add"}_invoice'

    if not request.user.has_perm(permission):
        raise PermissionDenied

    form = InvoiceForm(request.POST or None, instance=instance)
    items = Item.objects.values('id', 'title')
    invoice_items = []

    if instance:
        invoice_items = InvoiceItems.objects.filter(
            invoice_id=instance).select_related('item')

    if request.method == 'POST' and form.is_valid():
        invoice = form.save(commit=False)
        if not instance:
            invoice.created_by = request.user
        invoice.updated_by = request.user
        invoice.save()

        if instance:
            InvoiceItems.objects.filter(invoice_id=invoice.id).delete()

        total_forms = int(request.POST.get('form-TOTAL_FORMS', 0))
        for i in range(total_forms):
            item_id = request.POST.get(f'form-{i}-item')
            quantity = request.POST.get(f'form-{i}-quantity')
            unit_price = request.POST.get(f'form-{i}-unit_price')
            handling = request.POST.get(f'form-{i}-handling_charges')

            if item_id and quantity and unit_price:
                InvoiceItems.objects.create(
                    invoice_id=invoice,
                    item_id=item_id,
                    quantity=quantity,
                    unit_price=unit_price,
                    handling_charges=handling or 0
                )

        invoice.save()

        messages.success(
            request, f"Invoice #{invoice.id} {'updated' if instance else 'created'} successfully.")
        return redirect('invoice_list')

    return render(request, 'admin_pages/invoice_form.html', {
        'form': form,
        'items': list(items),
        'invoice_items': invoice_items,
        'addresses': Address.objects.all(),
        'title': 'Edit Invoice' if instance else 'Add Invoice',
        'invoice': instance

    })


@require_POST
def create_sender_api(request):
    try:
        sender = Sender.objects.create(
            name=request.POST.get('name'),
            last_name=request.POST.get('last_name'),
            fathers_name=request.POST.get('fathers_name'),
            mobile=request.POST.get('mobile'),
            email=request.POST.get('email'),
            home_phone=request.POST.get('home_phone'),
            street=request.POST.get('street'),
            city=request.POST.get('city'),
            State_province_area=request.POST.get('State_province_area'),
            postal_code=request.POST.get('postal_code'),
            country=request.POST.get('country')
        )
        return JsonResponse({'success': True, 'id': sender.id, 'text': str(sender)})
    except Exception as e:
        return JsonResponse({'success': False, 'error': str(e)})


@require_POST
def create_receiver_api(request):
    try:
        receiver = Receiver.objects.create(
            name=request.POST.get('name'),
            last_name=request.POST.get('last_name'),
            fathers_name=request.POST.get('fathers_name'),
            mobile=request.POST.get('mobile'),
            email=request.POST.get('email'),
            home_phone=request.POST.get('home_phone'),
            street=request.POST.get('street'),
            city=request.POST.get('city'),
            State_province_area=request.POST.get('State_province_area'),
            postal_code=request.POST.get('postal_code'),
            country=request.POST.get('country')
        )
        return JsonResponse({'success': True, 'id': receiver.id, 'text': str(receiver)})
    except Exception as e:
        return JsonResponse({'success': False, 'error': str(e)})


def item_search_api(request):
    q = request.GET.get("q", "")
    results = list(Item.objects.filter(
        title__icontains=q).values("id", "title")[:10])
    return JsonResponse(results, safe=False)


@permission_required('cargo.view_invoice', raise_exception=True)
def invoice_detail_view(request, pk):
    invoice = get_object_or_404(Invoice, pk=pk)
    return render(request, 'admin_pages/invoice_detail.html', {
        'invoice': invoice,
        'items': invoice.invoiceitems_set.all(),  # for inline display
    })


@permission_required('cargo.invoice_download_pdf', raise_exception=True)
def invoice_print_view(request, pk):
    company_profile = CompanyProfile.objects.first()
    company_rules = company_profile.companyrules_set.all()
    invoice = get_object_or_404(Invoice, pk=pk)
    items = invoice.invoiceitems_set.all()

    total_handling = sum(item.handling_charges for item in items)
    grand_total = sum((item.quantity * item.unit_price) +
                      item.handling_charges for item in items)
    total_amount = sum(item.quantity * item.unit_price for item in items)

    return render(request, 'admin_pages/invoice_print.html', {
        'company_profile': company_profile,
        'company_rules': company_rules,
        'invoice': invoice,
        'items': items,
        'total_handling': total_handling,
        'total_amount': total_amount,
        'grand_total': grand_total,
        'generated_at': now(),
    })


@permission_required('cargo.view_addexpense', raise_exception=True)
def print_expense_view(request, pk):
    expense = get_object_or_404(AddExpense, pk=pk)
    return render(request, 'admin_pages/print_expense.html', {
        'expense': expense,
        'now': now(),
    })


@permission_required('website.view_order_details', raise_exception=True)
def order_detail_view(request, pk, template_name='admin_pages/order_detail.html'):
    order = get_object_or_404(Order, pk=pk)

    # Handle status update
    if request.method == 'POST':
        if not request.user.has_perm('website.change_order'):
            raise PermissionDenied

        new_status = request.POST.get('status')
        if new_status and new_status != order.status:
            old_status = order.status
            order.status = new_status
            order.save()
            messages.success(
                request, f"Order status changed from <strong>{escape(old_status)}</strong> to <strong>{escape(new_status)}</strong>.")
            return redirect('order_details', pk=pk)

    return render(request, template_name, {
        'order': order,
        'items': order.items.all(),
        'can_edit': request.user.has_perm('website.change_order'),
        'status_choices': Order.STATUS_CHOICES,
    })


def blog(request):
    search_query = request.GET.get("search", "")
    category_id = request.GET.get("category")

    blog_posts = Blog.objects.all().order_by("-created_at")
    recent_posts = Blog.objects.order_by("-created_at")[:5]
    categories = Category.objects.all()

    # Search Filtering
    if search_query:
        blog_posts = blog_posts.filter(title__icontains=search_query)

    # Category Filtering
    if category_id:
        blog_posts = blog_posts.filter(category_id=category_id)

    # Pagination (6 posts per page)
    paginator = Paginator(blog_posts, 6)
    page_number = request.GET.get("page")
    blog_posts = paginator.get_page(page_number)

    return render(request, "shop/blog.html", {
        "blog_posts": blog_posts,
        "recent_posts": recent_posts,
        "categories": categories,
    })


def blog_detail(request, blog_id):
    post = get_object_or_404(Blog, id=blog_id)  # Ensure 'id' is used here
    return render(request, "shop/blog_detail.html", {"post": post})


@login_required
def add_to_wishlist(request, product_id):
    product = get_object_or_404(Product, id=product_id)
    wishlist_item, created = Wishlist.objects.get_or_create(
        user=request.user, product=product)

    if created:
        messages.success(request, f"{product.name} added to your wishlist!")
    else:
        messages.info(request, f"{product.name} is already in your wishlist.")

    return redirect('shop')


@login_required
def remove_from_wishlist(request, product_id):
    product = get_object_or_404(Product, id=product_id)
    Wishlist.objects.filter(user=request.user, product=product).delete()
    messages.success(request, f"{product.name} removed from your wishlist.")
    return redirect('wishlist')


@login_required
def wishlist(request):
    wishlist_items = Wishlist.objects.filter(user=request.user)
    return render(request, 'shop/wishlist.html', {'wishlist_items': wishlist_items})


@login_required
def submit_review(request, product_id):
    product = get_object_or_404(Product, id=product_id)

    if request.method == "POST":
        form = ReviewForm(request.POST)
        if form.is_valid():
            review = form.save(commit=False)
            review.user = request.user
            review.product = product
            review.save()
            messages.success(
                request, "Your review has been submitted successfully!")
            return redirect('product_detail', pk=product.id)
    else:
        form = ReviewForm()

    return render(request, "shop/submit_review.html", {"form": form, "product": product})


@login_required
def reply_to_review(request, review_id):
    review = get_object_or_404(Review, id=review_id)

    # ✅ Only allow staff (admins) to reply
    if not request.user.is_staff:
        messages.error(request, "You are not authorized to reply to reviews.")
        return redirect("product_detail", pk=review.product.id)

    if request.method == "POST":
        form = ReviewReplyForm(request.POST)
        if form.is_valid():
            reply = form.save(commit=False)
            reply.review = review
            reply.admin = request.user
            reply.save()
            messages.success(request, "Reply submitted successfully.")
            return redirect("product_detail", pk=review.product.id)
    else:
        form = ReviewReplyForm()

    return render(request, "shop/reply_to_review.html", {"form": form, "review": review})


def testimonials(request):
    testimonials = Testimonial.objects.filter(
        approved=True).order_by('-created_at')

    context = {
        'testimonials': testimonials
    }
    return render(request, 'shop/testimonials.html', context)


def testimonials_view(request):
    """Display only approved testimonials."""
    testimonials = Testimonial.objects.filter(
        approved=True).order_by("-created_at")
    return render(request, "shop/testimonials.html", {"testimonials": testimonials})


@login_required
def submit_testimonial_page(request):
    """Render the form for submitting a testimonial."""
    return render(request, "shop/submit_testimonial.html")


@login_required
def submit_testimonial(request):
    """Handle form submission for testimonials."""
    if request.method == "POST":
        message = request.POST.get("message")
        rating = request.POST.get("rating")

        if message and rating:
            Testimonial.objects.create(
                user=request.user,
                message=message,
                rating=int(rating),
                approved=False  # Requires admin approval
            )
            messages.success(
                request, "Your testimonial has been submitted for review.")
            return redirect("testimonials")  # Redirect to the testimonial page

    # If not a POST request, redirect to the form
    return redirect("submit_testimonial_page")


def contact(request):
    if request.method == "POST":
        name = request.POST['name']
        email = request.POST['email']
        subject = request.POST['subject']
        message = request.POST['message']

        # Validate email
        try:
            validate_email(email)
        except ValidationError:
            return JsonResponse({'status': 'error', 'message': 'Invalid email address. Please try again.'})

        email_message = f"Name: {name}\nEmail: {email}\n\nMessage:\n{message}"

        # Send the email
        try:
            send_mail(
                f"Contact Form Submission: {subject}",
                email_message,
                email,
                # Replace with your recipient/admin email
                ['nesarahmad.rishteen.nr@gmail.com'],
            )
            return JsonResponse({'status': 'success', 'message': 'Your email has been submitted!'})
        except Exception as e:
            return JsonResponse({'status': 'error', 'message': 'Something went wrong. Please try again later.'})

    return render(request, 'shop/contact.html')


def about_us(request):
    return render(request, 'shop/about_us.html')


def shop(request):
    category_id = request.GET.get('category')
    min_price = request.GET.get('min_price')
    max_price = request.GET.get('max_price')
    in_stock = request.GET.get('in_stock')
    rating = request.GET.get('rating')
    sort_by = request.GET.get('sort_by', 'default')  # Default sorting
    page = request.GET.get('page', 1)  # Get current page number

    categories = Category.objects.all()
    products = Product.objects.all()

    # ✅ Apply Filters
    if category_id:
        products = products.filter(category_id=category_id)
    if min_price and max_price:
        products = products.filter(price__gte=min_price, price__lte=max_price)
    if in_stock:
        products = products.filter(stock__gt=0)
    if rating:
        products = products.filter(rating__gte=rating)

    # ✅ Apply Sorting
    if sort_by == 'price_low':
        products = products.order_by('price')  # Low to High
    elif sort_by == 'price_high':
        products = products.order_by('-price')  # High to Low
    elif sort_by == 'newest':
        products = products.order_by('-created_at')  # Newest first
    elif sort_by == 'top_rated':
        products = products.order_by('-rating')  # Highest rated first
    else:
        products = products.order_by('-id')  # Default: newest first

    # ✅ Paginate with 9 products per page
    paginator = Paginator(products, 9)
    products_page = paginator.get_page(page)

    # ✅ Return JSON for AJAX (Infinite Scroll / Lazy Load)
    if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
        product_list = []
        for product in products_page:
            product_list.append({
                'id': product.id,
                'name': product.name,
                'image': product.image.url,
                'price': product.price,
                'detail_url': product.get_absolute_url(),
            })
        return JsonResponse({
            'products': product_list,
            'has_next': products_page.has_next()
        })

    # ✅ Render Template
    return render(request, 'shop/shop.html', {
        'categories': categories,
        'products': products_page,
        'selected_sort': sort_by  # Send the selected sorting to template
    })


def live_search(request):
    """Handles AJAX product search requests."""
    search_query = request.GET.get('search', '')
    if search_query:
        products = Product.objects.filter(name__icontains=search_query)[
            :6]  # Limit results for performance
        product_list = [
            {
                'id': product.id,
                'name': product.name,
                'image': product.image.url,
                'detail_url': product.get_absolute_url(),
            }
            for product in products
        ]
        return JsonResponse({'products': product_list})

    return JsonResponse({'products': []})


def compare_products(request):
    product1_id = request.GET.get("product1")
    product2_id = request.GET.get("product2")

    try:
        product1 = Product.objects.get(id=product1_id)
        product2 = Product.objects.get(id=product2_id)

        data = {
            "status": "success",
            "product1": {
                "name": product1.name,
                "image": product1.image.url if product1.image else "",
                "price": product1.price,
                "rating": product1.rating,
                "stock": product1.stock,
                "description": product1.description[:100] + "..."  # Truncated
            },
            "product2": {
                "name": product2.name,
                "image": product2.image.url if product2.image else "",
                "price": product2.price,
                "rating": product2.rating,
                "stock": product2.stock,
                "description": product2.description[:100] + "..."
            },
        }

        return JsonResponse(data)
    except Product.DoesNotExist:
        return JsonResponse({"status": "error", "message": "Invalid product selection"})


def rate_product(request, product_id):
    if request.method == "POST":
        product = get_object_or_404(Product, id=product_id)
        rating = int(request.POST.get('rating'))

        # Save rating (for now, just updating, ideally, use a model)
        product.rating = (product.rating + rating) / 2
        product.save()

        messages.success(request, "Thanks for rating this product! ⭐")

    # 🔥 Fix the URL reversal issue
    return redirect('product_detail', pk=product.pk)


def home(request):
    categories = Category.objects.all()
    products = Product.objects.all()
    slides = Slide.objects.all()
    featured_products = Product.objects.order_by(
        '?')[:4]  # Show 4 random products
    testimonials = Testimonial.objects.filter(approved=True).order_by(
        '-created_at')[:3]  # Latest 3 testimonials
    latest_blogs = Blog.objects.order_by('-created_at')[:3]  # Latest 3 blogs
    recent_faqs = FAQ.objects.filter(answers__isnull=False).distinct()[
        :4]  # Only FAQs with answers

    context = {
        'categories': categories,
        'products': products,
        'slides': slides,
        'featured_products': featured_products,
        'testimonials': testimonials,
        'latest_blogs': latest_blogs,
        'recent_faqs': recent_faqs,  # ✅ Add FAQs to the context
    }
    return render(request, 'shop/home.html', context)


def product_detail(request, pk):
    product = get_object_or_404(Product, pk=pk)

    # Find products in the same category (excluding the current product)
    similar_products = Product.objects.filter(
        category=product.category).exclude(id=product.id)[:4]

    # Find frequently bought together products
    frequently_bought = OrderItem.objects.filter(
        order__items__product=product
    ).exclude(product=product).values('product').annotate(count=Count('product')).order_by('-count')[:4]

    # Get popular products as a fallback if no similar products exist
    popular_products = Product.objects.annotate(
        num_orders=Count('orderitem')).order_by('-num_orders')[:4]

    # Combine recommendations (fallback to popular products)
    recommended_products = list(similar_products) + list(Product.objects.filter(
        id__in=[p['product'] for p in frequently_bought])) or popular_products

    # ✅ Track Recently Viewed Products using Session
    recently_viewed = request.session.get('recently_viewed', [])

    # Remove product if already in the list to avoid duplicates
    if pk in recently_viewed:
        recently_viewed.remove(pk)

    # Add the current product to the beginning of the list
    recently_viewed.insert(0, pk)

    # Limit the list to the last 5 viewed products
    recently_viewed = recently_viewed[:5]

    # Save updated list in session
    request.session['recently_viewed'] = recently_viewed

    # Fetch the recently viewed products from the database
    recently_viewed_products = Product.objects.filter(
        id__in=recently_viewed).exclude(id=product.id)

    return render(request, 'shop/product_detail.html', {
        'product': product,
        'recommended_products': recommended_products,
        'recently_viewed_products': recently_viewed_products
    })


def add_to_cart(request, product_id):
    product = get_object_or_404(Product, id=product_id)

    if request.user.is_authenticated:
        # Store the cart in the database for logged-in users
        cart, created = Cart.objects.get_or_create(user=request.user)
        cart_item, created = CartItem.objects.get_or_create(
            cart=cart, product=product)

        if not created:
            cart_item.quantity += 1
        cart_item.save()

        messages.success(request, f"Added {product.name} to your cart.")

    else:
        # ✅ Retrieve session cart or create a new one
        cart = request.session.get('cart', {})

        if str(product_id) in cart:
            cart[str(product_id)]['quantity'] += 1
            messages.success(
                request, f"Increased quantity of {product.name} in your cart.")
        else:
            cart[str(product_id)] = {
                'name': product.name,
                'price': float(product.price),
                'quantity': 1
            }
            messages.success(request, f"Added {product.name} to your cart.")

        request.session['cart'] = cart
        request.session.modified = True

        # ✅ Save the cart in cookies for 7 days
        response = redirect('cart_summary')
        response.set_cookie('saved_cart', json.dumps(cart),
                            max_age=604800)  # 7 days

        return response

    return redirect('shop')  # Redirect to the shop page


def add_to_cart_at_basket(request, product_id):
    product = get_object_or_404(Product, id=product_id)

    if request.user.is_authenticated:
        # Store in database for logged-in users
        cart, created = Cart.objects.get_or_create(user=request.user)
        cart_item, created = CartItem.objects.get_or_create(
            cart=cart, product=product)

        if not created:
            cart_item.quantity += 1
        cart_item.save()

        messages.success(request, f"Added {product.name} to your cart.")

    else:
        # Store in session for guests
        if 'cart' not in request.session:
            request.session['cart'] = {}

        cart = request.session['cart']

        if str(product_id) in cart:
            cart[str(product_id)]['quantity'] += 1
            messages.success(
                request, f"Increased quantity of {product.name} in your cart.")
        else:
            cart[str(product_id)] = {
                'name': product.name,
                'price': float(product.price),
                'quantity': 1
            }
            messages.success(request, f"Added {product.name} to your cart.")

        request.session['cart'] = cart
        request.session.modified = True

    return redirect('cart_summary')


def remove_from_cart(request, product_id):
    product = get_object_or_404(Product, id=product_id)

    if request.user.is_authenticated:
        # Remove from database-based cart
        cart, created = Cart.objects.get_or_create(user=request.user)
        cart_item = CartItem.objects.filter(cart=cart, product=product).first()

        if cart_item:
            if cart_item.quantity > 1:
                cart_item.quantity -= 1
                cart_item.save()
                messages.success(
                    request, f"Reduced quantity of {product.name} in your cart.")
            else:
                cart_item.delete()
                messages.success(
                    request, f"Removed {product.name} from your cart.")

    else:
        # ✅ Remove from session-based cart
        cart = request.session.get('cart', {})

        if str(product_id) in cart:
            if cart[str(product_id)]['quantity'] > 1:
                cart[str(product_id)]['quantity'] -= 1
                messages.success(
                    request, f"Reduced quantity of {product.name} in your cart.")
            else:
                del cart[str(product_id)]
                messages.success(
                    request, f"Removed {product.name} from your cart.")

        request.session['cart'] = cart
        request.session.modified = True

        # ✅ Update the cookie to reflect the new cart
        response = redirect('cart_summary')
        response.set_cookie('saved_cart', json.dumps(cart),
                            max_age=604800)  # 7 days

        return response

    return redirect('cart_summary')


def cart_summary(request):
    cart_items = []
    total_price = 0

    if request.user.is_authenticated:
        # Fetch cart from database for logged-in users
        cart, created = Cart.objects.get_or_create(user=request.user)
        cart_items = cart.cartitem_set.all()
        total_price = cart.get_total_price()

    else:
        # ✅ Check session cart first
        cart = request.session.get('cart', {})

        # ✅ If session cart is empty, check for a saved cart in cookies
        if not cart:
            cart_cookie = request.COOKIES.get('saved_cart')
            if cart_cookie:
                cart = json.loads(cart_cookie)

        for product_id, item in cart.items():
            product = Product.objects.get(id=product_id)
            cart_items.append({
                'product': product,
                'quantity': item['quantity'],
                'price': item['price'],
                'total': item['quantity'] * item['price']
            })

        total_price = sum(item['total'] for item in cart_items)

    response = render(request, 'shop/cart_summary.html', {
        'cart_items': cart_items,
        'total_price': total_price
    })

    return response


def clear_cart(request):
    if request.user.is_authenticated:
        # Remove all cart items for logged-in users
        cart, created = Cart.objects.get_or_create(user=request.user)
        cart.cartitem_set.all().delete()
    else:
        # Clear session cart for guest users
        request.session['cart'] = {}
        request.session.modified = True

        # Clear the saved cart cookie
        response = redirect('cart_summary')
        response.delete_cookie('saved_cart')

        messages.success(request, "Your cart has been cleared.")
        return response

    messages.success(request, "Your cart has been cleared.")
    return redirect('cart_summary')


@login_required
def checkout(request):
    # Merge session cart with user cart
    session_cart = request.session.get('cart', {})

    if session_cart:
        cart, created = Cart.objects.get_or_create(user=request.user)

        for product_id, item in session_cart.items():
            product = Product.objects.get(id=product_id)
            cart_item, created = CartItem.objects.get_or_create(
                cart=cart, product=product)
            cart_item.quantity += item['quantity']
            cart_item.save()

        # Clear session cart after merging
        request.session['cart'] = {}
        request.session.modified = True

    # Retrieve updated cart from database
    cart_items = CartItem.objects.filter(cart__user=request.user)
    total_price = sum(item.product.price *
                      item.quantity for item in cart_items)

    return render(request, 'shop/checkout.html', {'cart_items': cart_items, 'total_price': total_price})


@login_required
def process_checkout(request):
    if request.method == "POST":
        full_name = request.POST.get('full_name')
        address = request.POST.get('address')
        phone = request.POST.get('phone')
        payment_method = request.POST.get('payment_method')

        # Retrieve user's cart items
        cart_items = CartItem.objects.filter(cart__user=request.user)

        if not cart_items.exists():
            messages.error(request, "Your cart is empty!")
            return redirect('cart_summary')

        # Create an Order
        order = Order.objects.create(
            user=request.user,
            full_name=full_name,
            address=address,
            phone=phone,
            payment_method=payment_method,
            total_price=sum(item.product.price *
                            item.quantity for item in cart_items),
            status="Pending"
        )

        # Move cart items to the order
        for cart_item in cart_items:
            OrderItem.objects.create(
                order=order,
                product=cart_item.product,
                quantity=cart_item.quantity,
                price=cart_item.product.price
            )

        # Clear cart after checkout
        cart_items.delete()

        messages.success(request, "Your order has been placed successfully!")
        return redirect('order_success')

    return redirect('checkout')


def order_success(request):
    return render(request, 'shop/order_success.html')


def login_view(request):
    if request.method == "POST":
        username = request.POST["username"]
        password = request.POST["password"]
        user = authenticate(request, username=username, password=password)

        if user is not None:
            login(request, user)
            messages.success(request, "Login successful!")

            # ✅ Check for guest cart in session & cookies
            session_cart = request.session.get('cart', {})
            cart_cookie = request.COOKIES.get('saved_cart', '{}')
            cookie_cart = json.loads(cart_cookie) if cart_cookie else {}

            # ✅ Merge session and cookie carts
            guest_cart = {**session_cart, **cookie_cart}

            if guest_cart:
                cart, created = Cart.objects.get_or_create(user=user)

                for product_id, item in guest_cart.items():
                    product = Product.objects.get(id=product_id)
                    cart_item, created = CartItem.objects.get_or_create(
                        cart=cart, product=product)

                    # Increase quantity if already exists
                    cart_item.quantity += item['quantity']
                    cart_item.save()

                # ✅ Clear guest cart after merging
                request.session.pop('cart', None)
                # Redirect to cart page after login
                response = redirect("cart_summary")
                response.delete_cookie('saved_cart')

                return response

            return redirect("home")  # If no cart, redirect to home

        else:
            messages.error(request, "Invalid username or password!")

    return render(request, "shop/login.html")


def register_view(request):
    if request.method == "POST":
        username = request.POST["username"]
        email = request.POST["email"]
        password = request.POST["password"]
        confirm_password = request.POST["confirm_password"]

        if password != confirm_password:
            messages.error(request, "Passwords do not match!")
            return redirect("register")

        if User.objects.filter(username=username).exists():
            messages.error(request, "Username already exists!")
            return redirect("register")

        # ✅ Create and login user
        user = User.objects.create_user(
            username=username, email=email, password=password)
        login(request, user)
        messages.success(request, "Registration successful!")

        # ✅ Check for guest cart in session & cookies
        session_cart = request.session.get('cart', {})
        cart_cookie = request.COOKIES.get('saved_cart', '{}')
        cookie_cart = json.loads(cart_cookie) if cart_cookie else {}

        # ✅ Merge both session cart & cookie cart
        guest_cart = {**session_cart, **cookie_cart}

        if guest_cart:
            cart, created = Cart.objects.get_or_create(user=user)

            for product_id, item in guest_cart.items():
                product = Product.objects.get(id=product_id)
                cart_item, created = CartItem.objects.get_or_create(
                    cart=cart, product=product)

                # Increase quantity if already exists
                cart_item.quantity += item['quantity']
                cart_item.save()

            # ✅ Clear guest cart after merging
            request.session.pop('cart', None)
            # Redirect to cart page after registration
            response = redirect("cart_summary")
            response.delete_cookie('saved_cart')

            return response

        return redirect("home")  # If no cart, redirect to home

    return render(request, "shop/register.html")


@login_required
def profile_view(request):
    return render(request, 'shop/profile.html')


@login_required
def edit_profile(request):
    if request.method == 'POST':
        user_form = UserUpdateForm(request.POST, instance=request.user)
        profile_form = ProfileUpdateForm(
            request.POST, request.FILES, instance=request.user.profile)

        if user_form.is_valid() and profile_form.is_valid():
            user_form.save()
            profile_form.save()
            request.session['profile_updated'] = True
            return redirect('profile')
    else:
        user_form = UserUpdateForm(instance=request.user)
        profile_form = ProfileUpdateForm(instance=request.user.profile)

    # ✅ Read and clear the session flag BEFORE rendering
    profile_updated = request.session.pop('profile_updated', False)

    return render(request, 'shop/edit_profile.html', {
        'user_form': user_form,
        'profile_form': profile_form,
        'profile_updated': profile_updated,
    })


@login_required
def my_orders(request):
    # Get query parameters
    search_query = request.GET.get("search", "").strip()
    status_filter = request.GET.get("status", "")

    # Start with all orders for the logged-in user
    orders = Order.objects.filter(user=request.user).order_by("-created_at")

    # Apply search filter (Order ID)
    if search_query:
        orders = orders.filter(id__icontains=search_query)

    # Apply status filter
    if status_filter:
        orders = orders.filter(status=status_filter)

    return render(request, "shop/my_orders.html", {"orders": orders, "search_query": search_query, "status_filter": status_filter})


@login_required
def order_detail(request, order_id):
    order = get_object_or_404(Order, id=order_id, user=request.user)
    order_items = order.items.all()  # Fetch items in this order
    return render(request, "shop/order_detail.html", {"order": order, "order_items": order_items})



@login_required
def generate_invoice(request, order_id):
    order = get_object_or_404(Order, id=order_id, user=request.user)
    template = get_template("shop/invoice.html")
    html = template.render({"order": order})

    # Generate PDF
    pdf = pdfkit.from_string(html, False, configuration=pdfkit_config)

    response = HttpResponse(pdf, content_type="application/pdf")
    response["Content-Disposition"] = f'attachment; filename="invoice_{order.id}.pdf"'

    return response


@login_required
def submit_question(request):
    if request.method == "POST":
        form = FAQForm(request.POST)
        if form.is_valid():
            faq = form.save(commit=False)
            faq.user = request.user
            faq.save()
            messages.success(request, "Your question has been submitted!")
            return redirect("faq_page")
    else:
        form = FAQForm()
    return render(request, "shop/submit_question.html", {"form": form})


@login_required
def submit_answer(request, faq_id):
    faq = get_object_or_404(FAQ, id=faq_id)

    if request.method == "POST":
        form = FAQAnswerForm(request.POST)
        if form.is_valid():
            answer = form.save(commit=False)
            answer.faq = faq
            answer.user = request.user
            answer.save()
            messages.success(
                request, "Your answer has been submitted successfully ❤️")
            return redirect("faq_page")
    else:
        form = FAQAnswerForm()

    return render(request, "shop/submit_answer.html", {"form": form, "faq": faq})


@login_required
def admin_faq_dashboard(request):
    if not request.user.is_staff:
        messages.error(request, "You are not authorized to view this page.")
        return redirect("faq_page")

    unanswered_faqs = FAQ.objects.filter(is_answered=False)

    return render(request, "shop/admin_faq_dashboard.html", {"unanswered_faqs": unanswered_faqs})


def faq_page(request):
    from django.db.models import Count, Prefetch, Q

    # ✅ Base queryset with annotations
    faqs = FAQ.objects.annotate(
        total_likes=Count("likes", distinct=True),
        total_dislikes=Count("dislikes", distinct=True)
    ).prefetch_related(
        Prefetch(
            "answers",
            queryset=FAQAnswer.objects.annotate(
                total_likes=Count("likes", distinct=True),
                total_dislikes=Count("dislikes", distinct=True)
            ).select_related("user")
        )
    )

    # ✅ Handle sorting
    sort_option = request.GET.get("sort", "newest")
    if sort_option == "oldest":
        faqs = faqs.order_by("created_at")
    elif sort_option == "most_liked":
        faqs = faqs.order_by("-total_likes")
    else:
        faqs = faqs.order_by("-created_at")

    # ✅ Handle category filtering
    category_filter = request.GET.get("category")
    if category_filter:
        faqs = faqs.filter(category=category_filter)

    # ✅ Handle AJAX search
    if request.headers.get("X-Requested-With") == "XMLHttpRequest":
        search_query = request.GET.get("q", "").strip()
        filtered_faqs = faqs.filter(
            Q(question__icontains=search_query) |
            Q(answers__answer__icontains=search_query)
        ).distinct()

        results = []
        for faq in filtered_faqs:
            answers = []
            for ans in faq.answers.all():
                answers.append({
                    "id": ans.id,
                    "answer": ans.answer,
                    "user": ans.user.username if ans.user else "Anonymous",
                    "profile_image": ans.user.profile.image.url if ans.user and hasattr(ans.user, 'profile') and ans.user.profile.image else None,
                    "date": ans.created_at.strftime("%b %d, %Y"),
                    "total_likes": ans.total_likes,
                    "total_dislikes": ans.total_dislikes,
                })

            results.append({
                "id": faq.id,
                "question": faq.question,
                "user": faq.user.username if faq.user else "Anonymous",
                "profile_image": faq.user.profile.image.url if faq.user and hasattr(faq.user, 'profile') and faq.user.profile.image else None,
                "date": faq.created_at.strftime("%b %d, %Y"),
                "total_likes": faq.total_likes,
                "total_dislikes": faq.total_dislikes,
                "answers": answers,
            })

        return JsonResponse({"faqs": results})

    # ✅ Category and Sort filter buttons
    categories = [
        {"key": "", "label": "All"},
        {"key": "shipping", "label": "Shipping"},
        {"key": "payments", "label": "Payments"},
        {"key": "product", "label": "Product Info"},
        {"key": "returns", "label": "Returns"},
    ]

    sort_options = [
        {"key": "newest", "label": "Newest"},
        {"key": "oldest", "label": "Oldest"},
        {"key": "most_liked", "label": "Most Liked"},
    ]

    return render(request, "shop/faq_page.html", {
        "faqs": faqs,
        "categories": categories,
        "sort_options": sort_options,
    })


@csrf_exempt
def like_faq(request, faq_id):
    """Handles liking an FAQ"""
    faq = get_object_or_404(FAQ, id=faq_id)

    if request.user.is_authenticated:
        if request.user in faq.likes.all():
            faq.likes.remove(request.user)  # Remove like if already liked
        else:
            faq.likes.add(request.user)  # Add like
            faq.dislikes.remove(request.user)  # Ensure dislike is removed

        return JsonResponse({
            "total_likes": faq.likes.count(),
            "total_dislikes": faq.dislikes.count(),
        })
    return JsonResponse({"error": "User not authenticated"}, status=403)


@csrf_exempt
def dislike_faq(request, faq_id):
    """Handles disliking an FAQ"""
    faq = get_object_or_404(FAQ, id=faq_id)

    if request.user.is_authenticated:
        if request.user in faq.dislikes.all():
            # Remove dislike if already disliked
            faq.dislikes.remove(request.user)
        else:
            faq.dislikes.add(request.user)  # Add dislike
            faq.likes.remove(request.user)  # Ensure like is removed

        return JsonResponse({
            "total_likes": faq.likes.count(),
            "total_dislikes": faq.dislikes.count(),
        })
    return JsonResponse({"error": "User not authenticated"}, status=403)


@csrf_exempt
def like_answer(request, answer_id):
    """Handles liking an FAQ Answer"""
    answer = get_object_or_404(FAQAnswer, id=answer_id)

    if request.user.is_authenticated:
        if request.user in answer.likes.all():
            answer.likes.remove(request.user)
        else:
            answer.likes.add(request.user)
            answer.dislikes.remove(request.user)

        return JsonResponse({
            "total_likes": answer.likes.count(),
            "total_dislikes": answer.dislikes.count(),
        })
    return JsonResponse({"error": "User not authenticated"}, status=403)


@csrf_exempt
def dislike_answer(request, answer_id):
    """Handles disliking an FAQ Answer"""
    answer = get_object_or_404(FAQAnswer, id=answer_id)

    if request.user.is_authenticated:
        if request.user in answer.dislikes.all():
            answer.dislikes.remove(request.user)
        else:
            answer.dislikes.add(request.user)
            answer.likes.remove(request.user)

        return JsonResponse({
            "total_likes": answer.likes.count(),
            "total_dislikes": answer.dislikes.count(),
        })
    return JsonResponse({"error": "User not authenticated"}, status=403)


@login_required
def add_answer_comment(request, answer_id):
    answer = get_object_or_404(FAQAnswer, id=answer_id)

    if request.method == "POST":
        comment_text = request.POST.get("comment", "").strip()
        if comment_text:
            AnswerComment.objects.create(
                answer=answer,
                user=request.user,
                comment=comment_text,
            )
            messages.success(request, "Your comment has been posted!")

    return redirect("faq_page")


def cargo_info(request):
    return render(request, "shop/cargo_info.html")


def newsletter_subscribe(request):
    if request.method == "POST":
        email = request.POST.get("email")
        if email:
            if not NewsletterSubscriber.objects.filter(email=email).exists():
                NewsletterSubscriber.objects.create(email=email)
                messages.success(request, "Thank you for subscribing!")
            else:
                messages.info(request, "You're already subscribed.")
        else:
            messages.error(request, "Please enter a valid email.")
    return redirect(request.META.get("HTTP_REFERER", "/"))


def admin_page(request):
    return render(request, "admin_pages/dashboard.html")
