from django.contrib.auth.views import LoginView
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth import login, authenticate, logout
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from .models import Parcel, Profile, Country, Governate, City, OTPVerification, PlatformProfile, Testimonial, DriverRating
from .forms import UserRegistrationForm, ParcelForm, ContactForm, UserProfileForm, DriverRatingForm, ShipperRegistrationForm, DriverRegistrationForm
from django.utils.translation import gettext_lazy as _
from django.utils.translation import get_language
from django.contrib import messages
from django.http import JsonResponse, HttpResponse
from django.urls import reverse
from .payment_utils import ThawaniPay
from django.conf import settings
from django.core.mail import send_mail
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.views.decorators.http import require_POST
from django.db.models import Avg, Count
from django.template.loader import render_to_string
import random
import string
from .notifications import get_notification_content
from .whatsapp_utils import (
    notify_shipment_created, 
    notify_payment_received, 
    notify_driver_assigned, 
    notify_status_change,
    send_whatsapp_message
)
from .mail import send_contact_message, send_html_email
import json
from ai.local_ai_api import LocalAIApi
import weasyprint
import qrcode
from io import BytesIO
import base64
from .pricing import get_pricing_breakdown # Import pricing logic

def index(request):
    # If tracking_id is present, redirect to the new track view
    tracking_id = request.GET.get('tracking_id')
    if tracking_id:
        return redirect(f"{reverse('track')}?tracking_number={tracking_id}")
    
    testimonials = Testimonial.objects.filter(is_active=True)
    
    # Top 5 Drivers (by Average Rating)
    top_drivers = Profile.objects.filter(role='car_owner').annotate(
        avg_rating=Avg('user__received_ratings__rating'),
        rating_count=Count('user__received_ratings')
    ).filter(rating_count__gt=0).order_by('-avg_rating')[:5]
    
    # Top 5 Shippers (by Shipment Count)
    top_shippers = Profile.objects.filter(role='shipper').annotate(
        shipment_count=Count('user__sent_parcels')
    ).order_by('-shipment_count')[:5]
    
    return render(request, 'core/index.html', {
        'testimonials': testimonials,
        'top_drivers': top_drivers,
        'top_shippers': top_shippers
    })

def track_parcel(request):
    tracking_number = request.GET.get('tracking_number')
    parcel = None
    error = None
    
    if tracking_number:
        try:
            parcel = Parcel.objects.get(tracking_number__iexact=tracking_number.strip())
        except Parcel.DoesNotExist:
            error = _("Parcel not found with this Tracking ID.")
            
    return render(request, 'core/track.html', {
        'parcel': parcel,
        'error': error,
        'tracking_number': tracking_number
    })

def register(request):
    return render(request, 'core/register_choice.html')

def register_shipper(request):
    if request.method == 'POST':
        form = ShipperRegistrationForm(request.POST)
        if form.is_valid():
            # Save user but inactive
            user = form.save(commit=True)
            user.is_active = False
            user.save()

            # Auto-approve Shippers
            if hasattr(user, 'profile'):
                user.profile.is_approved = True
                user.profile.save()

            # Generate OTP
            code = ''.join(random.choices(string.digits, k=6))
            OTPVerification.objects.create(user=user, code=code, purpose='registration')

            # Send OTP
            method = form.cleaned_data.get('verification_method', 'email')
            subj, email_msg, wa_msg = get_notification_content('otp_registration', {'code': code}, language=get_language())
            
            if method == 'whatsapp':
                phone = user.profile.phone_number
                send_whatsapp_message(phone, wa_msg)
                messages.info(request, _("Verification code sent to WhatsApp."))
            else:
                send_html_email(
                    subject=subj,
                    message=email_msg,
                    recipient_list=[user.email],
                    title=_('Welcome to Masar!'),
                    request=request
                )
                messages.info(request, _("Verification code sent to email."))

            request.session['registration_user_id'] = user.id
            return redirect('verify_registration')
    else:
        form = ShipperRegistrationForm()
    return render(request, 'core/register_shipper.html', {'form': form})

def register_driver(request):
    if request.method == 'POST':
        form = DriverRegistrationForm(request.POST, request.FILES)
        if form.is_valid():
            # Save user but inactive
            user = form.save(commit=True)
            user.is_active = False
            user.save()
            
            # Drivers are NOT approved by default (model default is False)
            # We can rely on the default, but explicit is fine too if we want to be sure
            if hasattr(user, 'profile'):
                user.profile.is_approved = False
                user.profile.save()

            # Generate OTP
            code = ''.join(random.choices(string.digits, k=6))
            OTPVerification.objects.create(user=user, code=code, purpose='registration')

            # Send OTP
            method = form.cleaned_data.get('verification_method', 'email')
            subj, email_msg, wa_msg = get_notification_content('otp_registration', {'code': code}, language=get_language())
            
            if method == 'whatsapp':
                phone = user.profile.phone_number
                send_whatsapp_message(phone, wa_msg)
                messages.info(request, _("Verification code sent to WhatsApp."))
            else:
                send_html_email(
                    subject=subj,
                    message=email_msg,
                    recipient_list=[user.email],
                    title=_('Welcome to Masar!'),
                    request=request
                )
                messages.info(request, _("Verification code sent to email."))

            request.session['registration_user_id'] = user.id
            return redirect('verify_registration')
    else:
        form = DriverRegistrationForm()
    return render(request, 'core/register_driver.html', {'form': form})

def verify_registration(request):
    if 'registration_user_id' not in request.session:
        messages.error(request, _("Session expired or invalid."))
        return redirect('register')

    if request.method == 'POST':
        code = request.POST.get('code')
        user_id = request.session['registration_user_id']
        try:
            user = User.objects.get(id=user_id)
            otp = OTPVerification.objects.filter(
                user=user, 
                code=code, 
                purpose='registration', 
                is_verified=False
            ).latest('created_at')
            
            if otp.is_valid():
                # Activate User
                user.is_active = True
                user.save()
                
                # Cleanup
                otp.is_verified = True
                otp.save()
                del request.session['registration_user_id']
                
                # Login
                login(request, user)
                
                messages.success(request, _("Account verified successfully!"))
                return redirect('dashboard')
            else:
                messages.error(request, _("Invalid or expired code."))
        except (User.DoesNotExist, OTPVerification.DoesNotExist):
            messages.error(request, _("Invalid code."))
            
    return render(request, 'core/verify_registration.html')

@login_required
def dashboard(request):
    # Ensure profile exists
    profile, created = Profile.objects.get_or_create(user=request.user)

    if profile.role == 'shipper':
        all_parcels = Parcel.objects.filter(shipper=request.user).order_by('-created_at')
        active_parcels_list = all_parcels.exclude(status__in=['delivered', 'cancelled'])
        
        # Split history into delivered and cancelled
        delivered_parcels = all_parcels.filter(status='delivered')
        cancelled_parcels = all_parcels.filter(status='cancelled')
        
        # Pagination for Active Shipments
        page = request.GET.get('page', 1)
        paginator = Paginator(active_parcels_list, 9) # Show 9 parcels per page
        
        try:
            active_parcels = paginator.page(page)
        except PageNotAnInteger:
            active_parcels = paginator.page(1)
        except EmptyPage:
            active_parcels = paginator.page(paginator.num_pages)

        platform_profile = PlatformProfile.objects.first()
        payments_enabled = platform_profile.enable_payment if platform_profile else True
        
        return render(request, 'core/shipper_dashboard.html', {
            'active_parcels': active_parcels,
            'delivered_parcels': delivered_parcels,
            'cancelled_parcels': cancelled_parcels,
            'payments_enabled': payments_enabled,
            'platform_profile': platform_profile # Pass full profile just in case
        })
    else:
        # Car Owner view
        platform_profile = PlatformProfile.objects.first()
        payments_enabled = platform_profile.enable_payment if platform_profile else True
        
        if payments_enabled:
            available_parcels_list = Parcel.objects.filter(status='pending', payment_status='paid').order_by('-created_at')
        else:
            available_parcels_list = Parcel.objects.filter(status='pending').order_by('-created_at')

        # Check Approval Status
        if not profile.is_approved:
            messages.warning(request, _("Your account is pending approval. You cannot accept shipments yet."))
            # Empty list if not approved
            available_parcels_list = Parcel.objects.none()

        # Pagination for Available Shipments
        page = request.GET.get('page', 1)
        paginator = Paginator(available_parcels_list, 9) # Show 9 parcels per page
        
        try:
            available_parcels = paginator.page(page)
        except PageNotAnInteger:
            available_parcels = paginator.page(1)
        except EmptyPage:
            available_parcels = paginator.page(paginator.num_pages)

        # Active: Picked up or In Transit
        my_parcels = Parcel.objects.filter(carrier=request.user).exclude(status__in=['delivered', 'cancelled']).order_by('-created_at')
        
        # History: Delivered
        completed_parcels = Parcel.objects.filter(carrier=request.user, status='delivered').order_by('-created_at')
        
        # Cancelled
        cancelled_parcels = Parcel.objects.filter(carrier=request.user, status='cancelled').order_by('-created_at')
        
        return render(request, 'core/driver_dashboard.html', {
            'available_parcels': available_parcels,
            'my_parcels': my_parcels,
            'completed_parcels': completed_parcels,
            'cancelled_parcels': cancelled_parcels,
            'is_approved': profile.is_approved  # Pass to template
        })

@login_required
def shipment_request(request):
    profile, created = Profile.objects.get_or_create(user=request.user)
    if profile.role != 'shipper':
        messages.error(request, _("Only shippers can request shipments."))
        return redirect('dashboard')

    if request.method == 'POST':
        form = ParcelForm(request.POST)
        if form.is_valid():
            parcel = form.save(commit=False)
            parcel.shipper = request.user
            
            # Recalculate price on backend to ensure integrity
            # We trust the form's distance/weight if populated, but good to verify
            # Ideally we recalculate from PricingRule here too
            breakdown = get_pricing_breakdown(parcel.distance_km, parcel.weight)
            if 'error' not in breakdown:
                 parcel.price = breakdown['price']
                 parcel.platform_fee = breakdown['platform_fee']
                 parcel.platform_fee_percentage = breakdown['platform_fee_percentage']
                 parcel.driver_amount = breakdown['driver_amount']
            
            parcel.save()
            
            # WhatsApp Notification
            notify_shipment_created(parcel)
            
            messages.success(request, _("Shipment requested successfully! Tracking ID: ") + parcel.tracking_number)
            return redirect('dashboard')
    else:
        form = ParcelForm()
    
    platform_profile = PlatformProfile.objects.first()
    google_maps_api_key = platform_profile.google_maps_api_key if platform_profile else None
    
    return render(request, 'core/shipment_request.html', {
        'form': form,
        'google_maps_api_key': google_maps_api_key
    })

@login_required
def accept_parcel(request, parcel_id):
    profile, created = Profile.objects.get_or_create(user=request.user)
    if profile.role != 'car_owner':
        messages.error(request, _("Only car owners can accept shipments."))
        return redirect('dashboard')
    
    # Check Approval
    if not profile.is_approved:
        messages.error(request, _("Your account is pending approval. You cannot accept shipments yet."))
        return redirect('dashboard')

    platform_profile = PlatformProfile.objects.first()
    payments_enabled = platform_profile.enable_payment if platform_profile else True

    if payments_enabled:
        parcel = get_object_or_404(Parcel, id=parcel_id, status='pending', payment_status='paid')
    else:
        parcel = get_object_or_404(Parcel, id=parcel_id, status='pending')

    parcel.carrier = request.user
    parcel.status = 'picked_up'
    parcel.save()
    
    # WhatsApp Notification
    notify_driver_assigned(parcel)
    
    messages.success(request, _("You have accepted the shipment!"))
    return redirect('dashboard')

@login_required
def update_status(request, parcel_id):
    parcel = get_object_or_404(Parcel, id=parcel_id, carrier=request.user)
    if request.method == 'POST':
        new_status = request.POST.get('status')
        if new_status in dict(Parcel.STATUS_CHOICES):
            parcel.status = new_status
            parcel.save()
            
            # WhatsApp Notification
            notify_status_change(parcel)
            
            messages.success(request, _("Status updated successfully!"))
    return redirect('dashboard')

@login_required
def initiate_payment(request, parcel_id):
    # Check if payments are enabled
    platform_profile = PlatformProfile.objects.first()
    if platform_profile and not platform_profile.enable_payment:
        messages.error(request, _("Payments are currently disabled by the administrator."))
        return redirect('dashboard')

    parcel = get_object_or_404(Parcel, id=parcel_id, shipper=request.user, payment_status='pending')
    
    thawani = ThawaniPay()
    success_url = request.build_absolute_uri(reverse('payment_success')) + f"?session_id={{CHECKOUT_SESSION_ID}}&parcel_id={parcel.id}"
    cancel_url = request.build_absolute_uri(reverse('payment_cancel')) + f"?parcel_id={parcel.id}"
    
    session_id = thawani.create_checkout_session(parcel, success_url, cancel_url)
    
    if session_id:
        parcel.thawani_session_id = session_id
        parcel.save()
        checkout_url = f"{settings.THAWANI_API_URL.replace('/api/v1', '')}/pay/{session_id}?key={settings.THAWANI_PUBLISHABLE_KEY}"
        return redirect(checkout_url)
    else:
        messages.error(request, _("Could not initiate payment. Please try again later."))
        return redirect('dashboard')

@login_required
def payment_success(request):
    session_id = request.GET.get('session_id')
    parcel_id = request.GET.get('parcel_id')
    parcel = get_object_or_404(Parcel, id=parcel_id, shipper=request.user)
    
    thawani = ThawaniPay()
    session_data = thawani.get_checkout_session(session_id)
    
    if session_data and session_data.get('payment_status') == 'paid':
        parcel.payment_status = 'paid'
        parcel.save()
        
        # WhatsApp Notification
        notify_payment_received(parcel)
        
        messages.success(request, _("Payment successful! Your shipment is now active."))
    else:
        messages.warning(request, _("Payment status is pending or failed. Please check your dashboard."))
    
    return redirect('dashboard')

@login_required
def payment_cancel(request):
    messages.info(request, _("Payment was cancelled."))
    return redirect('dashboard')

def article_detail(request):
    return render(request, 'core/article_detail.html')

def get_governates(request):
    country_id = request.GET.get('country_id')
    lang = get_language()
    field_name = 'name_ar' if lang == 'ar' else 'name_en'
    governates = Governate.objects.filter(country_id=country_id).order_by(field_name)
    data = [{'id': g.id, 'name': getattr(g, field_name)} for g in governates]
    return JsonResponse(data, safe=False)

def get_cities(request):
    governate_id = request.GET.get('governate_id')
    lang = get_language()
    field_name = 'name_ar' if lang == 'ar' else 'name_en'
    cities = City.objects.filter(governate_id=governate_id).order_by(field_name)
    data = [{'id': c.id, 'name': getattr(c, field_name)} for c in cities]
    return JsonResponse(data, safe=False)

def privacy_policy(request):
    return render(request, 'core/privacy_policy.html')

def terms_conditions(request):
    return render(request, 'core/terms_conditions.html')

def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            # Send email
            sent = send_contact_message(
                name=form.cleaned_data['name'],
                email=form.cleaned_data['email'],
                message=form.cleaned_data['message']
            )
            if sent:
                messages.success(request, _("Your message has been sent successfully!"))
            else:
                messages.error(request, _("There was an error sending your message. Please try again later."))
            return redirect('contact')
    else:
        form = ContactForm()
    return render(request, 'core/contact.html', {'form': form})

@login_required
def profile_view(request):
    profile = request.user.profile
    reviews = []
    if profile.role == 'car_owner':
        reviews = request.user.received_ratings.all().order_by('-created_at')
    
    return render(request, 'core/profile.html', {
        'profile': profile,
        'reviews': reviews
    })

@login_required
def edit_profile(request):
    if request.method == 'POST':
        form = UserProfileForm(request.POST, request.FILES, instance=request.user.profile)
        if form.is_valid():
            # 1. Handle Image immediately (easier than session storage)
            if 'profile_picture' in request.FILES:
                request.user.profile.profile_picture = request.FILES['profile_picture']
                request.user.profile.save()

            # 2. Store other data in session for verification
            data = form.cleaned_data
            # Remove objects that can't be serialized or we've already handled
            safe_data = {
                'first_name': data['first_name'],
                'last_name': data['last_name'],
                'email': data['email'],
                'phone_number': data['phone_number'],
                'address': data['address'],
                'country_id': data['country'].id if data['country'] else None,
                'governate_id': data['governate'].id if data['governate'] else None,
                'city_id': data['city'].id if data['city'] else None,
            }
            request.session['pending_profile_update'] = safe_data

            # 3. Generate OTP
            code = ''.join(random.choices(string.digits, k=6))
            OTPVerification.objects.create(user=request.user, code=code, purpose='profile_update')

            # 4. Send OTP
            method = data.get('otp_method', 'email')
            subj, email_msg, wa_msg = get_notification_content('otp_profile_update', {'code': code}, language=get_language())
            
            if method == 'whatsapp':
                # Use current phone if available, else new phone
                phone = request.user.profile.phone_number or data['phone_number']
                send_whatsapp_message(phone, wa_msg)
                messages.info(request, _("Verification code sent to WhatsApp."))
            else:
                # Default to email
                # Send to the NEW email address (from the form), not the old one
                target_email = data['email']
                send_html_email(
                    subject=subj,
                    message=email_msg,
                    recipient_list=[target_email],
                    title=subj,
                    request=request
                )
                messages.info(request, _("Verification code sent to email."))

            return redirect('verify_otp')
    else:
        form = UserProfileForm(instance=request.user.profile)

    return render(request, 'core/edit_profile.html', {'form': form})

@login_required
def verify_otp_view(request):
    if request.method == 'POST':
        code = request.POST.get('code')
        try:
            otp = OTPVerification.objects.filter(
                user=request.user, 
                code=code, 
                purpose='profile_update', 
                is_verified=False
            ).latest('created_at')
            
            if otp.is_valid():
                # Apply changes
                data = request.session.get('pending_profile_update')
                if data:
                    # Update User
                    request.user.first_name = data['first_name']
                    request.user.last_name = data['last_name']
                    request.user.email = data['email']
                    request.user.save()
                    
                    # Update Profile
                    profile = request.user.profile
                    profile.phone_number = data['phone_number']
                    profile.address = data['address']
                    if data.get('country_id'):
                        profile.country_id = data['country_id']
                    if data.get('governate_id'):
                        profile.governate_id = data['governate_id']
                    if data.get('city_id'):
                        profile.city_id = data['city_id']
                    profile.save()
                    
                    # Cleanup
                    otp.is_verified = True
                    otp.save()
                    del request.session['pending_profile_update']
                    
                    messages.success(request, _("Profile updated successfully!"))
                    return redirect('profile')
                else:
                    messages.error(request, _("Session expired. Please try again."))
                    return redirect('edit_profile')
            else:
                messages.error(request, _("Invalid or expired code."))
        except OTPVerification.DoesNotExist:
            messages.error(request, _("Invalid code."))
            
    return render(request, 'core/verify_otp.html')

@login_required
def rate_driver(request, parcel_id):
    parcel = get_object_or_404(Parcel, id=parcel_id)
    
    # Validation
    if parcel.shipper != request.user:
        messages.error(request, _("You are not authorized to rate this shipment."))
        return redirect('dashboard')
        
    if parcel.status != 'delivered':
        messages.error(request, _("You can only rate delivered shipments."))
        return redirect('dashboard')
        
    if not parcel.carrier:
        messages.error(request, _("No driver was assigned to this shipment."))
        return redirect('dashboard')
        
    if hasattr(parcel, 'rating'):
        messages.info(request, _("You have already rated this shipment."))
        return redirect('dashboard')

    if request.method == 'POST':
        form = DriverRatingForm(request.POST)
        if form.is_valid():
            rating = form.save(commit=False)
            rating.parcel = parcel
            rating.driver = parcel.carrier
            rating.shipper = request.user
            rating.save()
            messages.success(request, _("Thank you for your feedback!"))
            return redirect('dashboard')
    else:
        form = DriverRatingForm()

    return render(request, 'core/rate_driver.html', {
        'form': form,
        'parcel': parcel
    })

@require_POST
def request_login_otp(request):
    identifier = request.POST.get('identifier')
    
    if not identifier:
        return JsonResponse({'success': False, 'message': _('Please enter an email or phone number.')})
    
    # Clean identifier
    identifier = identifier.strip()
    
    user = None
    method = 'email'
    
    # Try to find user by email
    user = User.objects.filter(email__iexact=identifier).first()
    
    # If not found, try by phone number
    if not user:
        profile = Profile.objects.filter(phone_number=identifier).first()
        if profile:
            user = profile.user
            method = 'whatsapp'
        else:
            # Fallback: maybe they entered a phone without country code or with?
            # For now, simplistic search
            pass
            
    if not user:
        # Don't reveal if user exists or not for security, but for UX on this project we can be a bit more helpful
        return JsonResponse({'success': False, 'message': _('User not found with this email or phone number.')})

    if not user.is_active:
        return JsonResponse({'success': False, 'message': _('Account is inactive. Please verify registration first.')})

    # Generate OTP
    code = ''.join(random.choices(string.digits, k=6))
    subj, email_msg, wa_msg = get_notification_content('otp_login', {'code': code}, language=get_language())
    OTPVerification.objects.create(user=user, code=code, purpose='login')
    
    # Send OTP
    subj, email_msg, wa_msg = get_notification_content('otp_login', {'code': code}, language=get_language())
    
    try:
        if method == 'whatsapp':
            phone = user.profile.phone_number
            send_whatsapp_message(phone, wa_msg)
            message_sent = _("OTP sent to your WhatsApp.")
        else:
            send_html_email(
                subject=subj,
                message=email_msg,
                recipient_list=[user.email],
                title=_('Login Verification'),
                request=request
            )
            message_sent = _("OTP sent to your email.")
            
        return JsonResponse({'success': True, 'message': message_sent, 'user_id': user.id})
    except Exception as e:
        return JsonResponse({'success': False, 'message': _('Failed to send OTP. Please try again.')})

@require_POST
def verify_login_otp(request):
    user_id = request.POST.get('user_id')
    code = request.POST.get('code')
    
    if not user_id or not code:
        return JsonResponse({'success': False, 'message': _('Invalid request.')})
        
    try:
        user = User.objects.get(id=user_id)
        otp = OTPVerification.objects.filter(
            user=user, 
            code=code, 
            purpose='login', 
            is_verified=False
        ).latest('created_at')
        
        if otp.is_valid():
            # Cleanup
            otp.is_verified = True
            otp.save()
            
            # Login
            login(request, user)
            
            return JsonResponse({'success': True, 'redirect_url': reverse('dashboard')})
        else:
            return JsonResponse({'success': False, 'message': _('Invalid or expired OTP.')})
            
    except (User.DoesNotExist, OTPVerification.DoesNotExist):
        return JsonResponse({'success': False, 'message': _('Invalid OTP.')})

@require_POST
def chatbot(request):
    try:
        data = json.loads(request.body)
        user_message = data.get("message", "")
        language = data.get("language", "en")
        
        if not user_message:
            return JsonResponse({"success": False, "error": "Empty message"})

        system_prompt = (
            "You are MasarX AI, a helpful and professional assistant for the Masar logistics platform. "
            "The platform connects shippers with drivers for small parcel deliveries. "
            "Answer the user's questions about shipping, tracking, becoming a driver, or general support. "
            "If the user speaks Arabic, reply in Arabic. If English, reply in English. "
            "Keep responses concise and helpful."
        )
        
        if language == "ar":
            system_prompt += " The user is currently browsing in Arabic."
        else:
            system_prompt += " The user is currently browsing in English."

        response = LocalAIApi.create_response({
            "input": [
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": user_message},
            ]
        })
        
        if response.get("success"):
            text = LocalAIApi.extract_text(response)
            return JsonResponse({"success": True, "response": text})
        else:
            return JsonResponse({"success": False, "error": response.get("error", "AI Error")})
            
    except json.JSONDecodeError:
        return JsonResponse({"success": False, "error": "Invalid JSON"})
    except Exception as e:
        return JsonResponse({"success": False, "error": str(e)})

@login_required
def generate_parcel_label(request, parcel_id):
    parcel = get_object_or_404(Parcel, id=parcel_id)
    
    # Security check: only shipper or carrier can print label
    if parcel.shipper != request.user and parcel.carrier != request.user:
        messages.error(request, _("You are not authorized to print this label."))
        return redirect('dashboard')

    # Generate QR Code
    qr = qrcode.QRCode(
        version=1,
        error_correction=qrcode.constants.ERROR_CORRECT_L,
        box_size=10,
        border=4,
    )
    qr.add_data(parcel.tracking_number)
    qr.make(fit=True)
    img = qr.make_image(fill_color="black", back_color="white")
    
    buffer = BytesIO()
    img.save(buffer, format="PNG")
    qr_image_base64 = base64.b64encode(buffer.getvalue()).decode()

    # Get Logo Base64
    logo_base64 = None
    platform_profile = PlatformProfile.objects.first()
    if platform_profile and platform_profile.logo:
        try:
            with open(platform_profile.logo.path, "rb") as image_file:
                logo_base64 = base64.b64encode(image_file.read()).decode()
        except Exception:
            pass

    # Render Template
    html_string = render_to_string('core/parcel_label.html', {
        'parcel': parcel,
        'qr_code': qr_image_base64,
        'logo_base64': logo_base64,
        'platform_profile': platform_profile,
    })

    # Generate PDF
    html = weasyprint.HTML(string=html_string, base_url=request.build_absolute_uri())
    pdf_file = html.write_pdf()

    response = HttpResponse(pdf_file, content_type='application/pdf')
    response['Content-Disposition'] = f'inline; filename="label_{parcel.tracking_number}.pdf"'
    return response

@login_required
def generate_invoice(request, parcel_id):
    parcel = get_object_or_404(Parcel, id=parcel_id)
    
    # Security check: only shipper can view invoice (or admin)
    if parcel.shipper != request.user and not request.user.is_staff:
        messages.error(request, _("You are not authorized to view this invoice."))
        return redirect('dashboard')

    # Get Logo Base64
    logo_base64 = None
    platform_profile = PlatformProfile.objects.first()
    if platform_profile and platform_profile.logo:
        try:
            with open(platform_profile.logo.path, "rb") as image_file:
                logo_base64 = base64.b64encode(image_file.read()).decode()
        except Exception:
            pass

    # Render Template
    html_string = render_to_string('core/invoice.html', {
        'parcel': parcel,
        'logo_base64': logo_base64,
        'platform_profile': platform_profile,
        'request': request,
    })

    # Generate PDF
    html = weasyprint.HTML(string=html_string, base_url=request.build_absolute_uri())
    pdf_file = html.write_pdf()

    response = HttpResponse(pdf_file, content_type='application/pdf')
    response['Content-Disposition'] = f'inline; filename="invoice_{parcel.tracking_number}.pdf"'
    return response

@login_required
def scan_qr_view(request):
    """Renders the QR Scanner page for drivers."""
    # Optional: Restrict to drivers only
    # if request.user.profile.role != 'car_owner':
    #     messages.error(request, _("Only drivers can access the scanner."))
    #     return redirect('dashboard')
    return render(request, 'core/scan_qr.html')

@login_required
def get_parcel_details(request):
    """API to fetch parcel details by tracking number."""
    tracking_number = request.GET.get('tracking_number')
    if not tracking_number:
        return JsonResponse({'success': False, 'error': _('Tracking number required')})
        
    try:
        parcel = Parcel.objects.get(tracking_number__iexact=tracking_number.strip())
        
        # Check permissions: Is user the assigned driver? Or is it pending (for acceptance)?
        is_driver = request.user.profile.role == 'car_owner'
        is_assigned = parcel.carrier == request.user
        
        can_update = False
        if is_driver:
            if is_assigned:
                can_update = True
            elif parcel.status == 'pending':
                # Check if payments are enabled and paid
                platform_profile = PlatformProfile.objects.first()
                payments_enabled = platform_profile.enable_payment if platform_profile else True
                if not payments_enabled or parcel.payment_status == 'paid':
                    can_update = True
        
        data = {
            'success': True,
            'parcel': {
                'id': parcel.id,
                'tracking_number': parcel.tracking_number,
                'status': parcel.status,
                'status_display': parcel.get_status_display(),
                'price': float(parcel.price),
                'from': f"{parcel.pickup_governate.name} / {parcel.pickup_city.name}",
                'to': f"{parcel.delivery_governate.name} / {parcel.delivery_city.name}",
                'description': parcel.description,
                'can_update': can_update
            }
        }
        return JsonResponse(data)
    except Parcel.DoesNotExist:
        return JsonResponse({'success': False, 'error': _('Parcel not found')})

@login_required
@require_POST
def update_parcel_status_ajax(request):
    """API to update parcel status from scanner."""
    try:
        data = json.loads(request.body)
        parcel_id = data.get('parcel_id')
        action = data.get('action')
        
        parcel = get_object_or_404(Parcel, id=parcel_id)
        
        # Logic for actions
        if action == 'accept':
            # Similar to accept_parcel view
            if request.user.profile.role != 'car_owner':
                return JsonResponse({'success': False, 'error': _('Only drivers can accept shipments')})
                
            if parcel.status != 'pending':
                return JsonResponse({'success': False, 'error': _('Parcel is not available')})
                
            # Check payment status if enabled
            platform_profile = PlatformProfile.objects.first()
            payments_enabled = platform_profile.enable_payment if platform_profile else True
            if payments_enabled and parcel.payment_status != 'paid':
                 return JsonResponse({'success': False, 'error': _('Payment pending')})
            
            # Check Approval for Driver via AJAX
            if not request.user.profile.is_approved:
                 return JsonResponse({'success': False, 'error': _('Account pending approval')})
            
            parcel.carrier = request.user
            parcel.status = 'picked_up' # Or 'assigned'? Logic says 'picked_up' in accept_parcel
            parcel.save()
            notify_driver_assigned(parcel)
            
        elif action == 'delivered':
             if parcel.carrier != request.user:
                 return JsonResponse({'success': False, 'error': _('Not authorized')})
             
             parcel.status = 'delivered'
             parcel.save()
             notify_status_change(parcel)
             
        else:
            return JsonResponse({'success': False, 'error': _('Invalid action')})
            
        return JsonResponse({'success': True})
        
    except Exception as e:
        return JsonResponse({'success': False, 'error': str(e)})

@login_required
def edit_parcel(request, parcel_id):
    parcel = get_object_or_404(Parcel, id=parcel_id, shipper=request.user)
    
    if parcel.status != 'pending':
        messages.error(request, _("You can only edit pending shipments."))
        return redirect('dashboard')
        
    if request.method == 'POST':
        form = ParcelForm(request.POST, instance=parcel)
        if form.is_valid():
            parcel_updated = form.save(commit=False)
            
            # Recalculate if fields changed
            breakdown = get_pricing_breakdown(parcel_updated.distance_km, parcel_updated.weight)
            if 'error' not in breakdown:
                 parcel_updated.price = breakdown['price']
                 parcel_updated.platform_fee = breakdown['platform_fee']
                 parcel_updated.platform_fee_percentage = breakdown['platform_fee_percentage']
                 parcel_updated.driver_amount = breakdown['driver_amount']
            
            parcel_updated.save()
            
            messages.success(request, _("Shipment updated successfully."))
            return redirect('dashboard')
    else:
        form = ParcelForm(instance=parcel)
    
    platform_profile = PlatformProfile.objects.first()
    google_maps_api_key = platform_profile.google_maps_api_key if platform_profile else None
        
    return render(request, 'core/edit_parcel.html', {'form': form, 'parcel': parcel, 'google_maps_api_key': google_maps_api_key})

@login_required
def cancel_parcel(request, parcel_id):
    parcel = get_object_or_404(Parcel, id=parcel_id, shipper=request.user)
    
    if parcel.status != 'pending':
        messages.error(request, _("You can only cancel pending shipments."))
    else:
        parcel.status = 'cancelled'
        parcel.save()
        messages.success(request, _("Shipment cancelled successfully."))
        
    return redirect('dashboard')
class CustomLoginView(LoginView):
    template_name = 'core/login.html'

    def form_valid(self, form):
        # Authenticate checks are done by the form
        user = form.get_user()
        
        # Store user ID in session for 2FA step
        self.request.session['pre_2fa_user_id'] = user.id
        self.request.session.set_expiry(600) # 10 minutes expiry for this session part
        
        return redirect('select_2fa_method')

def select_2fa_method(request):
    user_id = request.session.get('pre_2fa_user_id')
    if not user_id:
        return redirect('login')
    
    try:
        user = User.objects.get(id=user_id)
    except User.DoesNotExist:
        return redirect('login')
    
    if request.method == 'POST':
        method = request.POST.get('method')
        code = ''.join(random.choices(string.digits, k=6))
        subj, email_msg, wa_msg = get_notification_content('otp_login', {'code': code}, language=get_language())
        
        # Invalidate old login OTPs
        OTPVerification.objects.filter(user=user, purpose='login').delete()
        OTPVerification.objects.create(user=user, code=code, purpose='login')
        
        if method == 'email':
            if user.email:
                try:
                    send_html_email(
                        subject=_("Your Login OTP"),
                        message=email_msg,
                        recipient_list=[user.email],
                        title=_("Login Verification")
                    )
                    messages.success(request, _("OTP sent to your email."))
                    return redirect('verify_2fa_otp')
                except Exception as e:
                     messages.error(request, _("Failed to send email: ") + str(e))
            else:
                messages.error(request, _("No email address associated with this account."))
                
        elif method == 'whatsapp':
             if hasattr(user, 'profile') and user.profile.phone_number:
                if send_whatsapp_message(user.profile.phone_number, wa_msg):
                    messages.success(request, _("OTP sent to your WhatsApp."))
                    return redirect('verify_2fa_otp')
                else:
                    messages.error(request, _("Failed to send WhatsApp message. Please check the logs."))
             else:
                messages.error(request, _("No phone number found for this account."))
        
    return render(request, 'core/select_2fa_method.html')

def verify_2fa_otp(request):
    user_id = request.session.get('pre_2fa_user_id')
    if not user_id:
        return redirect('login')
        
    try:
        user = User.objects.get(id=user_id)
    except User.DoesNotExist:
        return redirect('login')
    
    if request.method == 'POST':
        code = request.POST.get('otp')
        
        try:
            # Find the most recent valid login OTP for this user
            otp_record = OTPVerification.objects.filter(
                user=user, 
                purpose='login', 
                is_verified=False
            ).latest('created_at')
            
            if otp_record.code == code and otp_record.is_valid():
                otp_record.is_verified = True
                otp_record.save()
                
                # ACTUAL LOGIN HAPPENS HERE
                login(request, user)
                
                # Clean up session
                if 'pre_2fa_user_id' in request.session:
                    del request.session['pre_2fa_user_id']
                request.session.set_expiry(None)
                
                messages.success(request, _("Logged in successfully."))
                return redirect('dashboard')
            else:
                messages.error(request, _("Invalid or expired OTP."))
                
        except OTPVerification.DoesNotExist:
             messages.error(request, _("No valid OTP found. Please request a new one."))
             
    return render(request, 'core/verify_2fa_otp.html')