"""
Staff Dashboard Views - Separate from Admin Panel
Only accessible to staff users with permissions controlled by admin
"""
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required, user_passes_test
from django.contrib.auth import authenticate, login, logout
from django.contrib import messages
from django.db.models import Sum, Count, Q
from django.utils import timezone
from datetime import timedelta
from io import BytesIO

from products.models import Product, Category, ProductImage, ProductVariation
from orders.models import Order, OrderItem
from accounts.models import User
from django.core.mail import send_mail
from django.conf import settings
from decimal import Decimal
from payments.models import FinancialAccount, Transaction, Revenue, Expense, TaxRecord
from django.utils import timezone
from django.http import HttpResponse
from django.core.files.base import ContentFile
from payments.utils import FinancialReportGenerator
from django.urls import reverse
from .captcha import generate_captcha, validate_captcha
from django.utils.dateparse import parse_datetime
from notifications.models import Conversation, ConversationParticipant, Message
from django.core.cache import cache
from decimal import Decimal


def _scan_file_placeholder(f):
    try:
        _ = getattr(f, 'size', 0)
        return True
    except Exception:
        return True

def staff_login(request):
    """Staff email-based login"""
    context = {}
    if request.method == 'POST':
        ip = request.META.get('REMOTE_ADDR') or 'unknown'
        key = f"staff_login_attempts:{ip}"
        attempts = cache.get(key, 0)
        if attempts >= 5:
            context['error'] = 'Too many login attempts. Please try again later.'
            context['captcha_code'] = generate_captcha(request)
            return render(request, 'staff/login.html', context)
        email = (request.POST.get('username') or request.POST.get('email') or '').strip()
        password = request.POST.get('password') or ''
        captcha_value = request.POST.get('captcha', '')
        if not validate_captcha(request, captcha_value):
            context['error'] = 'Invalid captcha. Please try again.'
            context['captcha_code'] = generate_captcha(request)
            return render(request, 'staff/login.html', context)
        if not email or not password:
            context['error'] = 'Please enter both email and password.'
            context['captcha_code'] = generate_captcha(request)
            return render(request, 'staff/login.html', context)
        user = authenticate(request, username=email, password=password)
        if user is None:
            cache.set(key, attempts + 1, 300)
            context['error'] = 'Invalid email or password.'
            context['captcha_code'] = generate_captcha(request)
            return render(request, 'staff/login.html', context)
        if not getattr(user, "is_staff_member", False):
            cache.set(key, attempts + 1, 300)
            context['error'] = 'This account is not authorized for the staff portal.'
            context['captcha_code'] = generate_captcha(request)
            return render(request, 'staff/login.html', context)
        login(request, user)
        cache.delete(key)
        if not getattr(user, "kyc_approved", False):
            return redirect('staff:kyc')
        next_url = request.POST.get('next') or '/staff/dashboard/'
        return redirect(next_url)
    context['captcha_code'] = generate_captcha(request)
    return render(request, 'staff/login.html', context)


def staff_logout(request):
    """Staff Logout - accepts both GET and POST"""
    logout(request)
    messages.success(request, 'You have been logged out successfully.')
    return redirect('staff:login')


def is_staff_user(user):
    """Check if user is staff"""
    return bool(user.is_authenticated and getattr(user, "is_staff_member", False))


@login_required(login_url='/staff/login/')
@user_passes_test(is_staff_user, login_url='/staff/login/')
def staff_dashboard(request):
    """
    Staff Dashboard - Main page
    Shows different data based on user role
    """
    user = request.user
    
    # Base context
    context = {
        'user': user,
        'role': user.get_role_display(),
    }
    
    # Role-specific data
    if (getattr(user, 'is_admin', False) or user.role in [User.Role.STAFF_ADMIN, User.Role.ACCOUNTANT]):
        # Sales data for last 30 days
        thirty_days_ago = timezone.now() - timedelta(days=30)
        recent_orders = Order.objects.filter(created_at__gte=thirty_days_ago)
        
        context.update({
            'total_orders': recent_orders.count(),
            'total_revenue': recent_orders.filter(is_paid=True).aggregate(
                total=Sum('total')
            )['total'] or 0,
            'pending_orders': recent_orders.filter(status='PENDING').count(),
        })
    
    if user.has_permission('manage_inventory'):
        context.update({
            'total_products': Product.objects.filter(is_active=True).count(),
            'low_stock_products': Product.objects.filter(
                track_inventory=True,
                stock__lte=10
            ).count(),
        })
    
    if user.has_permission('manage_orders'):
        context.update({
            'pending_orders_list': Order.objects.filter(
                status='PENDING'
            ).select_related('user')[:10],
        })
    
    return render(request, 'staff/dashboard.html', context)

@login_required(login_url='/staff/login/')
@user_passes_test(is_staff_user, login_url='/staff/login/')
def staff_admin_dashboard(request):
    user = request.user
    if not (user.is_admin or user.role == User.Role.STAFF_ADMIN):
        messages.error(request, 'You do not have permission to access Staff Admin.')
        return redirect('staff:dashboard')
    thirty_days_ago = timezone.now() - timedelta(days=30)
    recent_orders = Order.objects.filter(created_at__gte=thirty_days_ago)
    total_revenue = recent_orders.filter(is_paid=True).aggregate(total=Sum('total'))['total'] or Decimal('0')
    total_products = Product.objects.filter(is_active=True).count()
    pending_products = Product.objects.filter(approval_status='PENDING').count()
    from vendors.models import Vendor
    pending_vendors = Vendor.objects.filter(status='PENDING').count()
    context = {
        'total_orders': recent_orders.count(),
        'total_revenue': total_revenue,
        'total_products': total_products,
        'pending_products': pending_products,
        'pending_vendors': pending_vendors,
    }
    return render(request, 'staff/admin_dashboard.html', context)

@login_required(login_url='/staff/login/')
@user_passes_test(is_staff_user, login_url='/staff/login/')
def staff_manage_staff(request):
    user = request.user
    if not (user.is_admin or user.role == User.Role.STAFF_ADMIN):
        messages.error(request, 'You do not have permission to manage staff.')
        return redirect('staff:dashboard')
    roles = [choice[0] for choice in User.Role.choices]
    staff_roles = [User.Role.ADMIN, User.Role.STAFF_ADMIN, User.Role.ACCOUNTANT, User.Role.INVENTORY_MANAGER, User.Role.SALES_MANAGER, User.Role.CUSTOMER_SUPPORT, User.Role.CONTENT_MANAGER, User.Role.MARKETING]
    staff_users = User.objects.filter(role__in=staff_roles).order_by('email')
    if request.method == 'POST':
        target_id = request.POST.get('user_id')
        new_role = request.POST.get('role')
        try:
            target = User.objects.get(id=int(target_id))
        except Exception:
            messages.error(request, 'Invalid staff user.')
            return redirect('staff:manage_staff')
        if target.is_superuser and not user.is_admin:
            messages.error(request, 'Only Admin can modify superuser.')
            return redirect('staff:manage_staff')
        if new_role not in roles:
            messages.error(request, 'Invalid role.')
            return redirect('staff:manage_staff')
        if target.id == user.id and target.role != new_role and not user.is_admin:
            messages.error(request, 'You cannot change your own role.')
            return redirect('staff:manage_staff')
        target.role = new_role
        target.save(update_fields=['role'])
        messages.success(request, 'Role updated.')
        return redirect('staff:manage_staff')
    context = {
        'staff_users': staff_users,
        'roles': staff_roles,
    }
    return render(request, 'staff/staff_management.html', context)

@login_required(login_url='/staff/login/')
@user_passes_test(is_staff_user, login_url='/staff/login/')
def staff_chat(request):
    user = request.user
    conv_id = request.GET.get('c') or ''
    target_user_id = request.POST.get('target_user_id') or ''
    action = request.POST.get('action') or ''
    body = (request.POST.get('body') or '').strip()
    selected = None
    if action == 'start' and target_user_id:
        try:
            target = User.objects.get(id=int(target_user_id))
        except Exception:
            messages.error(request, 'User not found.')
            return redirect('staff:chat')
        def is_staff_member(u):
            return getattr(u, 'is_staff_member', False)
        def is_staff_admin(u):
            return (getattr(u, 'role', None) == User.Role.STAFF_ADMIN) or getattr(u, 'is_admin', False)
        def is_customer(u):
            return getattr(u, 'role', None) == User.Role.CUSTOMER
        def is_vendor(u):
            return getattr(u, 'role', None) == User.Role.VENDOR
        # Policy:
        # - Non-admin staff can ONLY chat with Staff Admin
        # - Only Staff Admin (or Admin) can chat with Customers
        # - Vendors are not part of staff chat
        allowed = (
            (is_staff_admin(user) and (is_staff_member(target) or is_customer(target))) or
            (is_staff_member(user) and not is_staff_admin(user) and is_staff_admin(target))
        )
        if not allowed:
            messages.error(request, 'Chat not allowed for these roles.')
            return redirect('staff:chat')
        existing = Conversation.objects.filter(
            is_group=False,
            participants__user=user
        ).filter(
            participants__user=target
        ).distinct().first()
        if existing:
            return redirect(f"{reverse('staff:chat')}?c={existing.id}")
        conv = Conversation.objects.create(created_by=user, is_group=False)
        ConversationParticipant.objects.bulk_create([
            ConversationParticipant(conversation=conv, user=user),
            ConversationParticipant(conversation=conv, user=target),
        ])
        return redirect(f"{reverse('staff:chat')}?c={conv.id}")
    if action == 'send':
        post_conv_id = request.POST.get('conv_id') or conv_id
        if not post_conv_id or not body:
            return redirect('staff:chat')
        if len(body) > 200:
            messages.error(request, 'Message too long (max 200 characters)')
            try:
                cid = int(post_conv_id)
                return redirect(f"{reverse('staff:chat')}?c={cid}")
            except Exception:
                return redirect('staff:chat')
        try:
            conv = Conversation.objects.get(id=int(post_conv_id))
        except Exception:
            messages.error(request, 'Conversation not found.')
            return redirect('staff:chat')
        if not ConversationParticipant.objects.filter(conversation=conv, user=user).exists():
            messages.error(request, 'You are not a participant.')
            return redirect('staff:chat')
        # Enforce policy on send
        other = None
        try:
            for p in conv.participants.select_related('user').all():
                if p.user_id != user.id:
                    other = p.user
                    break
        except Exception:
            other = None
        def is_staff_member(u):
            return getattr(u, 'is_staff_member', False)
        def is_staff_admin(u):
            return (getattr(u, 'role', None) == User.Role.STAFF_ADMIN) or getattr(u, 'is_admin', False)
        def is_customer(u):
            return getattr(u, 'role', None) == User.Role.CUSTOMER
        allowed_send = (
            other is not None and (
                (is_staff_admin(user) and (is_staff_member(other) or is_customer(other))) or
                (is_staff_member(user) and not is_staff_admin(user) and is_staff_admin(other))
            )
        )
        if not allowed_send:
            messages.error(request, 'Chat not allowed for these roles.')
            return redirect('staff:chat')
        Message.objects.create(conversation=conv, sender=user, body=body)
        return redirect(f"{reverse('staff:chat')}?c={conv.id}")
    conv_ids = ConversationParticipant.objects.filter(user=user).values_list('conversation_id', flat=True)
    conversations = Conversation.objects.filter(id__in=list(conv_ids)).order_by('-last_message_at', '-created_at')
    conv_details = []
    for c in conversations:
        other = None
        try:
            parts = c.participants.select_related('user').all()
            for p in parts:
                if p.user_id != user.id:
                    other = p.user
                    break
        except Exception:
            other = None
        # Filter conversations by policy
        def is_staff_member(u):
            return getattr(u, 'is_staff_member', False)
        def is_staff_admin(u):
            return (getattr(u, 'role', None) == User.Role.STAFF_ADMIN) or getattr(u, 'is_admin', False)
        def is_customer(u):
            return getattr(u, 'role', None) == User.Role.CUSTOMER
        allowed_other = (
            other is not None and (
                (is_staff_admin(user) and (is_staff_member(other) or is_customer(other))) or
                (is_staff_member(user) and not is_staff_admin(user) and is_staff_admin(other))
            )
        )
        if allowed_other:
            conv_details.append({'conv': c, 'other': other})
    messages_qs = []
    selected_other = None
    if conv_id:
        try:
            selected = Conversation.objects.get(id=int(conv_id))
            if ConversationParticipant.objects.filter(conversation=selected, user=user).exists():
                messages_qs = Message.objects.filter(conversation=selected).select_related('sender').order_by('created_at')
                try:
                    parts_sel = selected.participants.select_related('user').all()
                    for p in parts_sel:
                        if p.user_id != user.id:
                            selected_other = p.user
                            break
                except Exception:
                    selected_other = None
                # Enforce selected conversation policy
                def is_staff_member(u):
                    return getattr(u, 'is_staff_member', False)
                def is_staff_admin(u):
                    return (getattr(u, 'role', None) == User.Role.STAFF_ADMIN) or getattr(u, 'is_admin', False)
                def is_customer(u):
                    return getattr(u, 'role', None) == User.Role.CUSTOMER
                allowed_selected = (
                    selected_other is not None and (
                        (is_staff_admin(user) and (is_staff_member(selected_other) or is_customer(selected_other))) or
                        (is_staff_member(user) and not is_staff_admin(user) and is_staff_admin(selected_other))
                    )
                )
                if not allowed_selected:
                    selected = None
                    messages.error(request, 'Chat not allowed for these roles.')
            else:
                selected = None
        except Exception:
            selected = None
    # Restrict users list to allowed targets
    def is_staff_admin(u):
        return (getattr(u, 'role', None) == User.Role.STAFF_ADMIN) or getattr(u, 'is_admin', False)
    if is_staff_admin(user):
        users_list = User.objects.filter(
            is_active=True
        ).filter(
            Q(role__in=[
                User.Role.ADMIN,
                User.Role.STAFF_ADMIN,
                User.Role.ACCOUNTANT,
                User.Role.INVENTORY_MANAGER,
                User.Role.SALES_MANAGER,
                User.Role.CUSTOMER_SUPPORT,
                User.Role.CONTENT_MANAGER,
                User.Role.MARKETING,
            ]) | Q(role=User.Role.CUSTOMER)
        ).exclude(id=user.id).order_by('email')[:50]
    else:
        users_list = User.objects.filter(
            is_active=True
        ).filter(
            Q(role=User.Role.STAFF_ADMIN) | Q(role=User.Role.ADMIN)
        ).exclude(id=user.id).order_by('email')[:50]
    context = {
        'conversations': conversations,
        'conv_details': conv_details,
        'selected': selected,
        'selected_other': selected_other,
        'chat_messages': messages_qs,
        'users_list': users_list,
    }
    return render(request, 'staff/chat.html', context)

@login_required(login_url='/staff/login/')
@user_passes_test(is_staff_user, login_url='/staff/login/')
def staff_manage_vendors(request):
    user = request.user
    if not (user.is_admin or user.role == User.Role.STAFF_ADMIN):
        messages.error(request, 'You do not have permission to manage vendors.')
        return redirect('staff:dashboard')
    from vendors.models import Vendor
    status = request.GET.get('status') or ''
    vendors = Vendor.objects.all().order_by('-created_at')
    if status in ['PENDING', 'ACTIVE', 'SUSPENDED', 'CLOSED']:
        vendors = vendors.filter(status=status)
    search = request.GET.get('search') or ''
    if search:
        vendors = vendors.filter(store_name__icontains=search)
    if request.method == 'POST':
        action = request.POST.get('action')
        vendor_id = request.POST.get('vendor_id')
        try:
            v = Vendor.objects.get(id=int(vendor_id))
        except Exception:
            messages.error(request, 'Vendor not found.')
            return redirect('staff:manage_vendors')
        if action == 'approve_kyc':
            v.kyc_approved = True
            v.status = 'ACTIVE'
            v.approved_at = timezone.now()
            v.save(update_fields=['kyc_approved', 'status', 'approved_at'])
            messages.success(request, 'Vendor KYC approved.')
        elif action == 'suspend':
            v.status = 'SUSPENDED'
            v.save(update_fields=['status'])
            messages.success(request, 'Vendor suspended.')
        elif action == 'activate':
            v.status = 'ACTIVE'
            v.save(update_fields=['status'])
            messages.success(request, 'Vendor activated.')
        elif action == 'close':
            v.status = 'CLOSED'
            v.save(update_fields=['status'])
            messages.success(request, 'Vendor closed.')
        return redirect('staff:manage_vendors')
    context = {
        'vendors': vendors,
        'selected_status': status,
        'search_query': search,
    }
    return render(request, 'staff/vendor_management.html', context)

@login_required(login_url='/staff/login/')
@user_passes_test(is_staff_user, login_url='/staff/login/')
def staff_vendor_detail(request, vendor_id):
    user = request.user
    if not (user.is_admin or user.role == User.Role.STAFF_ADMIN or user.has_permission('manage_orders')):
        messages.error(request, 'You do not have permission to view vendor details.')
        return redirect('staff:dashboard')
    from vendors.models import Vendor, VendorStore
    try:
        vendor = Vendor.objects.get(id=int(vendor_id))
    except Exception:
        messages.error(request, 'Vendor not found.')
        return redirect('staff:manage_vendors')
    products = Product.objects.filter(vendor=vendor).select_related('category', 'store')
    stores = VendorStore.objects.filter(vendor=vendor).order_by('name')
    item_qs = OrderItem.objects.filter(product__vendor=vendor).select_related('order')
    order_ids = list(item_qs.values_list('order_id', flat=True).distinct())
    recent_orders = Order.objects.filter(id__in=order_ids).order_by('-created_at')[:25]
    total_orders = len(order_ids)
    total_revenue = item_qs.aggregate(total=Sum('total_price'))['total'] or Decimal('0')
    try:
        from vendors.models import VendorCommission
        available_balance = VendorCommission.objects.filter(vendor=vendor, is_paid=False).aggregate(
            total=Sum('vendor_payout')
        )['total'] or Decimal('0')
    except Exception:
        available_balance = Decimal('0')
    context = {
        'vendor': vendor,
        'products': products,
        'stores': stores,
        'recent_orders': recent_orders,
        'total_orders': total_orders,
        'total_revenue': total_revenue,
        'available_balance': available_balance,
    }
    return render(request, 'staff/vendor_detail.html', context)
@login_required(login_url='/staff/login/')
@user_passes_test(is_staff_user, login_url='/staff/login/')
def staff_products(request):
    """Staff Products Management"""
    if not (
        request.user.has_permission('manage_inventory')
        or request.user.has_permission('manage_products')
        or getattr(request.user, "is_admin", False)
    ):
        messages.error(request, 'You do not have permission to manage products.')
        return redirect('staff:dashboard')
    
    from vendors.models import VendorStore
    products = Product.objects.all().select_related('category', 'store', 'vendor')
    
    # Search
    search = request.GET.get('search')
    if search:
        products = products.filter(name__icontains=search)
    
    category_id = request.GET.get('category')
    store_id = request.GET.get('store')
    product_id = request.GET.get('product')
    status = request.GET.get('status')
    if category_id:
        try:
            products = products.filter(category_id=int(category_id))
        except Exception:
            pass
    if product_id:
        try:
            products = products.filter(id=int(product_id))
        except Exception:
            pass
    if store_id:
        try:
            products = products.filter(store_id=int(store_id))
        except Exception:
            pass
    if status in ('PENDING', 'APPROVED', 'REJECTED'):
        products = products.filter(approval_status=status)
    
    categories = Category.objects.all().order_by('name')
    stores = VendorStore.objects.filter(is_active=True).order_by('name')
    product_options = Product.objects.values('id', 'name', 'category_id').order_by('name')
    
    context = {
        'products': products,
        'total_products': products.count(),
        'categories': categories,
        'stores': stores,
        'selected_category': category_id or '',
        'selected_store': store_id or '',
        'selected_product': product_id or '',
        'selected_status': status or '',
        'product_options': product_options,
        'search_query': search or '',
    }
    
    return render(request, 'staff/products.html', context)


@login_required(login_url='/staff/login/')
@user_passes_test(is_staff_user, login_url='/staff/login/')
def staff_products_bulk_action(request):
    """Staff Bulk Product Actions"""
    if not (
        request.user.has_permission('manage_inventory')
        or request.user.has_permission('manage_products')
        or getattr(request.user, "is_admin", False)
    ):
        messages.error(request, 'Permission denied.')
        return redirect('staff:products')

    if request.method != 'POST':
        return redirect('staff:products')
        
    action = request.POST.get('action', '')
    codes = request.POST.getlist('product_ids')
    codes = [c for c in codes if c]
    
    if not codes:
        messages.warning(request, 'Select at least one product')
        return redirect('staff:products')
        
    # Filter products - staff can edit any product
    qs = Product.objects.filter(id__in=codes)
    updated = 0
    
    if action == 'set_sale':
        try:
            sale_percentage = request.POST.get('sale_percentage')
            sale_start = request.POST.get('sale_start')
            sale_end = request.POST.get('sale_end')
            
            pct = Decimal(sale_percentage) if sale_percentage else Decimal('0')
            if pct > 0:
                for p in qs:
                    if p.price:
                        if not p.compare_price:
                            p.compare_price = p.price
                        
                        discount = (p.price * pct) / 100
                        p.sale_price = p.price - discount
                        
                        if sale_start:
                            p.sale_start = parse_datetime(sale_start)
                        else:
                            p.sale_start = timezone.now()
                            
                        if sale_end:
                            p.sale_end = parse_datetime(sale_end)
                        else:
                            p.sale_end = None
                            
                        p.save()
                        updated += 1
                messages.success(request, f'Sale applied to {updated} product(s)')
            else:
                for p in qs:
                    p.sale_price = None
                    p.sale_start = None
                    p.sale_end = None
                    p.save()
                    updated += 1
                messages.success(request, f'Sale removed from {updated} product(s)')
        except Exception as e:
            messages.error(request, f'Error setting sale: {e}')
            
    elif action == 'set_stock':
        try:
            new_stock = int(request.POST.get('stock_value', '0'))
            if new_stock < 0: new_stock = 0
            updated = qs.update(stock=new_stock)
            messages.success(request, f'Stock set to {new_stock} for {updated} product(s)')
        except Exception:
            messages.error(request, 'Invalid stock value')
            
    elif action == 'live_on':
        for p in qs:
            if p.approval_status == 'APPROVED':
                p.is_active = True
                p.save(update_fields=['is_active'])
                updated += 1
        messages.success(request, f'Live ON for {updated} approved product(s)')
        
    elif action == 'live_off':
        qs.update(is_active=False)
        messages.success(request, f'Live OFF for {qs.count()} product(s)')
        
    else:
        messages.warning(request, 'Invalid action')
        
    return redirect('staff:products')


@login_required(login_url='/staff/login/')
@user_passes_test(is_staff_user, login_url='/staff/login/')
def staff_orders(request):
    """Staff Orders Management"""
    if not request.user.has_permission('manage_orders'):
        messages.error(request, 'You do not have permission to view orders.')
        return redirect('staff:dashboard')
    
    if request.method == 'POST':
        action = request.POST.get('action')
        order_id = request.POST.get('order_id')
        try:
            order = Order.objects.select_related('user').get(id=order_id)
        except Order.DoesNotExist:
            messages.error(request, 'Order not found.')
            return redirect('staff:orders')
        
        if action in ('mark_paid', 'refund'):
            if not (getattr(request.user, 'is_admin', False) or request.user.role in [User.Role.STAFF_ADMIN, User.Role.ACCOUNTANT]):
                messages.error(request, 'You do not have permission to perform this action.')
                return redirect('staff:orders')
        
        if action == 'mark_paid':
            order.is_paid = True
            if order.status == Order.OrderStatus.PENDING:
                order.status = Order.OrderStatus.CONFIRMED
            order.save(update_fields=['is_paid', 'status'])
            
            cash_acc, _ = FinancialAccount.objects.get_or_create(
                code='1000',
                defaults={'name': 'Cash', 'account_type': 'ASSET'}
            )
            sales_acc, _ = FinancialAccount.objects.get_or_create(
                code='4000',
                defaults={'name': 'Sales Revenue', 'account_type': 'REVENUE'}
            )
            
            txn = Transaction.objects.create(
                transaction_type='SALE',
                description=f'Sale for Order {order.order_code}',
                amount=order.total,
                debit_account=cash_acc,
                credit_account=sales_acc,
                order=order,
                created_by=request.user
            )
            
            Revenue.objects.create(
                revenue_type='PRODUCT_SALE',
                description=f'Order {order.order_code} revenue',
                gross_amount=order.subtotal,
                discount=order.discount,
                tax_amount=order.tax,
                net_amount=order.total,
                order=order,
                transaction=txn,
                revenue_date=order.created_at.date()
            )
            
            messages.success(request, f'Order {order.order_code} marked as paid and recorded in finance.')
            return redirect('staff:orders')
        
        if action == 'refund':
            order.status = Order.OrderStatus.REFUNDED
            order.save(update_fields=['status'])
            
            cash_acc, _ = FinancialAccount.objects.get_or_create(
                code='1000',
                defaults={'name': 'Cash', 'account_type': 'ASSET'}
            )
            refund_exp_acc, _ = FinancialAccount.objects.get_or_create(
                code='6000',
                defaults={'name': 'Refunds Expense', 'account_type': 'EXPENSE'}
            )
            
            txn = Transaction.objects.create(
                transaction_type='REFUND',
                description=f'Refund for Order {order.order_code}',
                amount=order.total,
                debit_account=refund_exp_acc,
                credit_account=cash_acc,
                order=order,
                created_by=request.user
            )
            
            Expense.objects.create(
                expense_number='',
                category='REFUND',
                description=f'Refund issued for Order {order.order_code}',
                amount=order.total,
                tax_amount=Decimal('0'),
                payment_method=order.payment_method,
                payment_status='PAID',
                transaction=txn,
                expense_date=timezone.now().date(),
                created_by=request.user
            )
            
            messages.success(request, f'Order {order.order_code} refunded and recorded in finance.')
            return redirect('staff:orders')
    
    orders = Order.objects.all().select_related('user').order_by('-created_at')
    
    # Filter by status
    status = request.GET.get('status')
    if status:
        orders = orders.filter(status=status)
    
    try:
        order_ids = list(orders.values_list('id', flat=True))
        items = OrderItem.objects.filter(order_id__in=order_ids).select_related('product__vendor')
        vendors_by_order = {}
        for it in items:
            v = getattr(it.product, 'vendor', None)
            if v:
                code = getattr(v, 'vendor_code', None) or getattr(v, 'store_name', None) or 'Vendor'
                vendors_by_order.setdefault(it.order_id, {})[v.id] = code
            if not v:
                vendors_by_order.setdefault(it.order_id, {})[None] = 'Site'
        for o in orders:
            data = vendors_by_order.get(o.id, {})
            o.vendors_list = [{'id': vid, 'code': vcode} for vid, vcode in sorted(data.items(), key=lambda x: x[1])]
    except Exception:
        for o in orders:
            o.vendors_list = []
    
    context = {
        'orders': orders,
        'total_orders': orders.count(),
        'order_statuses': Order.OrderStatus.choices,
    }
    
    return render(request, 'staff/orders.html', context)


@login_required(login_url='/staff/login/')
@user_passes_test(is_staff_user, login_url='/staff/login/')
def staff_order_detail(request, order_code):
    """Detailed view of a single order for staff"""
    if not request.user.has_permission('manage_orders'):
        messages.error(request, 'You do not have permission to view orders.')
        return redirect('staff:dashboard')
    
    order = get_object_or_404(Order, order_code=order_code)
    order_items = OrderItem.objects.filter(order=order).select_related('product')
    
    context = {
        'order': order,
        'order_items': order_items,
        'staff_back_url': reverse('staff:orders'),
    }
    
    return render(request, 'pages/order_detail.html', context)


@login_required(login_url='/staff/login/')
@user_passes_test(is_staff_user, login_url='/staff/login/')
def staff_analytics(request):
    """Staff Analytics Dashboard"""
    if not (getattr(request.user, 'is_admin', False) or request.user.role in [User.Role.STAFF_ADMIN, User.Role.ACCOUNTANT]):
        messages.error(request, 'You do not have permission to view analytics.')
        return redirect('staff:dashboard')
    
    days = int(request.GET.get('days', 30))
    start_date = timezone.now() - timedelta(days=days)
    vendor_id = request.GET.get('vendor') or ''
    category_id = request.GET.get('category') or ''
    product_id = request.GET.get('product') or ''
    
    order_items = OrderItem.objects.select_related('order', 'product')\
        .filter(order__created_at__gte=start_date, order__is_paid=True)
    if vendor_id:
        try:
            order_items = order_items.filter(product__vendor_id=int(vendor_id))
        except Exception:
            pass
    if category_id:
        try:
            order_items = order_items.filter(product__category_id=int(category_id))
        except Exception:
            pass
    if product_id:
        try:
            order_items = order_items.filter(product_id=int(product_id))
        except Exception:
            pass
    
    total_orders = order_items.values('order_id').distinct().count()
    total_revenue = order_items.aggregate(total=Sum('total_price'))['total'] or Decimal('0')
    avg_order_value = total_revenue / total_orders if total_orders > 0 else Decimal('0')
    total_customers = Order.objects.filter(
        id__in=order_items.values('order_id').distinct()
    ).values('user_id').distinct().count()
    
    top_product_ids = list(order_items.values_list('product_id', flat=True))
    top_products = Product.objects.filter(id__in=top_product_ids).annotate(
        sales=Sum('orderitem__quantity'),
        revenue=Sum('orderitem__total_price')
    ).order_by('-sales')[:10]
    
    vendors = []
    try:
        from vendors.models import Vendor
        vendors = Vendor.objects.all().order_by('store_name')
    except Exception:
        vendors = []
    categories = Category.objects.all().order_by('name')
    product_options = Product.objects.values('id', 'name', 'category_id').order_by('name')
    
    context = {
        'total_orders': total_orders,
        'total_revenue': total_revenue,
        'avg_order_value': avg_order_value,
        'total_customers': total_customers,
        'top_products': top_products,
        'days': days,
        'vendors': vendors,
        'categories': categories,
        'product_options': product_options,
        'selected_vendor': vendor_id,
        'selected_category': category_id,
        'selected_product': product_id,
    }
    
    return render(request, 'staff/analytics.html', context)


@login_required(login_url='/staff/login/')
@user_passes_test(is_staff_user, login_url='/staff/login/')
def staff_ledger(request):
    """Staff Ledger - Browse Transactions, Revenues, Expenses"""
    if not (request.user.is_admin or request.user.has_permission('manage_finance')):
        messages.error(request, 'You do not have permission to view the finance ledger.')
        return redirect('staff:dashboard')
    
    days_default = int(request.GET.get('days', 30))
    end_date = request.GET.get('end_date')
    start_date = request.GET.get('start_date')
    
    if end_date:
        try:
            end_date = timezone.datetime.fromisoformat(end_date).date()
        except Exception:
            end_date = timezone.now().date()
    else:
        end_date = timezone.now().date()
    
    if start_date:
        try:
            start_date = timezone.datetime.fromisoformat(start_date).date()
        except Exception:
            start_date = end_date - timezone.timedelta(days=days_default)
    else:
        start_date = end_date - timezone.timedelta(days=days_default)
    
    txn_type = request.GET.get('transaction_type') or ''
    rev_type = request.GET.get('revenue_type') or ''
    exp_cat = request.GET.get('expense_category') or ''
    
    transactions = Transaction.objects.select_related('debit_account', 'credit_account', 'order', 'created_by')\
        .filter(transaction_date__date__gte=start_date, transaction_date__date__lte=end_date)\
        .order_by('-transaction_date')
    if txn_type:
        transactions = transactions.filter(transaction_type=txn_type)
    
    revenues = Revenue.objects.select_related('order', 'vendor', 'transaction')\
        .filter(revenue_date__gte=start_date, revenue_date__lte=end_date)\
        .order_by('-revenue_date')
    if rev_type:
        revenues = revenues.filter(revenue_type=rev_type)
    
    expenses = Expense.objects.select_related('transaction', 'created_by')\
        .filter(expense_date__gte=start_date, expense_date__lte=end_date)\
        .order_by('-expense_date')
    if exp_cat:
        expenses = expenses.filter(category=exp_cat)
    
    context = {
        'transactions': transactions,
        'revenues': revenues,
        'expenses': expenses,
        'txn_types': Transaction.TRANSACTION_TYPE_CHOICES,
        'rev_types': Revenue.REVENUE_TYPE_CHOICES,
        'exp_categories': Expense.EXPENSE_CATEGORY_CHOICES,
        'total_txn_amount': transactions.aggregate(total=Sum('amount'))['total'] or 0,
        'total_revenue_net': revenues.aggregate(total=Sum('net_amount'))['total'] or 0,
        'total_expense_amount': expenses.aggregate(total=Sum('amount'))['total'] or 0,
        'start_date': start_date,
        'end_date': end_date,
        'selected_txn_type': txn_type,
        'selected_rev_type': rev_type,
        'selected_exp_cat': exp_cat,
        'days_default': days_default,
    }
    
    return render(request, 'staff/ledger.html', context)


@login_required(login_url='/staff/login/')
@user_passes_test(is_staff_user, login_url='/staff/login/')
def staff_ledger_export(request):
    """Export CSV for Transactions, Revenues, or Expenses"""
    if not (request.user.is_admin or request.user.has_permission('manage_finance')):
        messages.error(request, 'You do not have permission to export finance data.')
        return redirect('staff:dashboard')
    
    data_type = request.GET.get('type')
    start_date = request.GET.get('start_date')
    end_date = request.GET.get('end_date')
    try:
        end = timezone.datetime.fromisoformat(end_date).date() if end_date else timezone.now().date()
        start = timezone.datetime.fromisoformat(start_date).date() if start_date else (end - timezone.timedelta(days=30))
    except Exception:
        end = timezone.now().date()
        start = end - timezone.timedelta(days=30)
    
    if data_type == 'transactions':
        qs = Transaction.objects.filter(transaction_date__date__gte=start, transaction_date__date__lte=end).order_by('-transaction_date')
        # Build transaction-specific CSV headers/rows inline
        import csv
        from io import StringIO
        output = StringIO()
        writer = csv.writer(output)
        writer.writerow(['Date/Time', 'Number', 'Type', 'Description', 'Amount', 'Debit', 'Credit', 'Order'])
        for t in qs:
            writer.writerow([
                t.transaction_date.strftime('%Y-%m-%d %H:%M'),
                t.transaction_number,
                t.get_transaction_type_display(),
                t.description,
                f"{t.amount}",
                t.debit_account.name,
                t.credit_account.name,
                t.order.order_number if t.order else ''
            ])
        csv_data = output.getvalue()
        resp = HttpResponse(csv_data, content_type='text/csv')
        resp['Content-Disposition'] = f'attachment; filename="transactions_{start}_{end}.csv"'
        return resp
    
    if data_type == 'cash_flow':
        inflow = Transaction.objects.filter(
            transaction_date__date__gte=start,
            transaction_date__date__lte=end,
            debit_account__code='1000'
        ).aggregate(total=Sum('amount'))['total'] or 0
        outflow = Transaction.objects.filter(
            transaction_date__date__gte=start,
            transaction_date__date__lte=end,
            credit_account__code='1000'
        ).aggregate(total=Sum('amount'))['total'] or 0
        import csv
        from io import StringIO
        output = StringIO()
        writer = csv.writer(output)
        writer.writerow(['Period Start', 'Period End', 'Inflow', 'Outflow', 'Net'])
        writer.writerow([start, end, inflow, outflow, (inflow - outflow)])
        csv_data = output.getvalue()
        resp = HttpResponse(csv_data, content_type='text/csv')
        resp['Content-Disposition'] = f'attachment; filename="cash_flow_{start}_{end}.csv"'
        return resp
    
    if data_type == 'revenues':
        qs = Revenue.objects.filter(revenue_date__gte=start, revenue_date__lte=end).order_by('-revenue_date')
        from payments.utils import FinancialReportGenerator
        csv_data = FinancialReportGenerator.export_to_csv(qs, filename=f"revenues_{start}_{end}.csv")
        resp = HttpResponse(csv_data, content_type='text/csv')
        resp['Content-Disposition'] = f'attachment; filename="revenues_{start}_{end}.csv"'
        return resp
    
    if data_type == 'expenses':
        qs = Expense.objects.filter(expense_date__gte=start, expense_date__lte=end).order_by('-expense_date')
        from payments.utils import FinancialReportGenerator
        csv_data = FinancialReportGenerator.export_to_csv(qs, filename=f"expenses_{start}_{end}.csv")
        resp = HttpResponse(csv_data, content_type='text/csv')
        resp['Content-Disposition'] = f'attachment; filename="expenses_{start}_{end}.csv"'
        return resp
    
    if data_type == 'balance_sheet':
        qs = FinancialAccount.objects.all().order_by('account_type', 'code')
        import csv
        from io import StringIO
        output = StringIO()
        writer = csv.writer(output)
        writer.writerow(['Code', 'Name', 'Type', 'Current Balance'])
        for acc in qs:
            writer.writerow([acc.code, acc.name, acc.account_type, f"{acc.current_balance}"])
        csv_data = output.getvalue()
        resp = HttpResponse(csv_data, content_type='text/csv')
        resp['Content-Disposition'] = f'attachment; filename="balance_sheet_accounts_{end}.csv"'
        return resp
    
    if data_type == 'tax':
        qs = TaxRecord.objects.filter(period_start__gte=start, period_end__lte=end).order_by('-period_end')
        import csv
        from io import StringIO
        output = StringIO()
        writer = csv.writer(output)
        writer.writerow(['Tax Type', 'Description', 'Rate', 'Taxable', 'Tax', 'Period Start', 'Period End', 'Paid', 'Paid Date'])
        for t in qs:
            writer.writerow([
                t.get_tax_type_display(),
                t.description,
                f"{t.tax_rate}",
                f"{t.taxable_amount}",
                f"{t.tax_amount}",
                t.period_start,
                t.period_end,
                'Yes' if t.is_paid else 'No',
                t.paid_date or ''
            ])
        csv_data = output.getvalue()
        resp = HttpResponse(csv_data, content_type='text/csv')
        resp['Content-Disposition'] = f'attachment; filename="tax_summary_{start}_{end}.csv"'
        return resp
    
    messages.error(request, 'Invalid export type.')
    return redirect('staff:ledger')


@login_required(login_url='/staff/login/')
@user_passes_test(is_staff_user, login_url='/staff/login/')
def staff_generate_report(request):
    """Generate monthly financial PDF report for accountants"""
    if request.method != 'POST':
        return redirect('staff:ledger')
    
    if not (request.user.is_admin or request.user.has_permission('manage_finance')):
        messages.error(request, 'You do not have permission to generate reports.')
        return redirect('staff:dashboard')
    
    month = request.POST.get('month')  # format YYYY-MM
    try:
        year, mon = map(int, month.split('-'))
        start_date = timezone.datetime(year, mon, 1).date()
        # compute end of month
        if mon == 12:
            end_date = timezone.datetime(year + 1, 1, 1).date() - timezone.timedelta(days=1)
        else:
            end_date = timezone.datetime(year, mon + 1, 1).date() - timezone.timedelta(days=1)
    except Exception:
        messages.error(request, 'Invalid month format.')
        return redirect('staff:ledger')
    
    report = FinancialReportGenerator.generate_income_statement(start_date, end_date)
    report.generated_by = request.user
    report.save(update_fields=['generated_by'])
    
    pdf_bytes = FinancialReportGenerator.generate_income_statement_pdf(report)
    if pdf_bytes:
        filename = f"income_statement_{start_date}_{end_date}.pdf"
        report.report_file.save(filename, ContentFile(pdf_bytes), save=True)
        resp = HttpResponse(pdf_bytes, content_type='application/pdf')
        resp['Content-Disposition'] = f'attachment; filename="{filename}"'
        messages.success(request, 'Monthly PDF report generated.')
        return resp
    
    messages.warning(request, 'PDF generation library not installed. Export CSV instead.')
    return redirect(f"{request.build_absolute_uri('/staff/ledger/export/')}?type=revenues&start_date={start_date}&end_date={end_date}")


@login_required(login_url='/staff/login/')
@user_passes_test(is_staff_user, login_url='/staff/login/')
def staff_generate_balance_sheet_report(request):
    """Generate balance sheet PDF"""
    if request.method != 'POST':
        return redirect('staff:ledger')
    if not (request.user.is_admin or request.user.has_permission('manage_finance')):
        messages.error(request, 'You do not have permission to generate reports.')
        return redirect('staff:dashboard')
    date_str = request.POST.get('as_of_date')
    try:
        as_of_date = timezone.datetime.fromisoformat(date_str).date()
    except Exception:
        as_of_date = timezone.now().date()
    report = FinancialReportGenerator.generate_balance_sheet(as_of_date)
    report.generated_by = request.user
    report.save(update_fields=['generated_by'])
    pdf_bytes = FinancialReportGenerator.generate_balance_sheet_pdf(report)
    if pdf_bytes:
        filename = f"balance_sheet_{as_of_date}.pdf"
        report.report_file.save(filename, ContentFile(pdf_bytes), save=True)
        resp = HttpResponse(pdf_bytes, content_type='application/pdf')
        resp['Content-Disposition'] = f'attachment; filename="{filename}"'
        messages.success(request, 'Balance sheet PDF generated.')
        return resp
    messages.warning(request, 'PDF generation library not installed. Export CSV instead.')
    return redirect(f"{request.build_absolute_uri('/staff/ledger/export/')}?type=balance_sheet&end_date={as_of_date}")


@login_required(login_url='/staff/login/')
@user_passes_test(is_staff_user, login_url='/staff/login/')
def staff_generate_cash_flow_report(request):
    if request.method != 'POST':
        return redirect('staff:ledger')
    if not (request.user.is_admin or request.user.has_permission('manage_finance')):
        messages.error(request, 'You do not have permission to generate reports.')
        return redirect('staff:dashboard')
    start_date = request.POST.get('start_date')
    end_date = request.POST.get('end_date')
    try:
        start = timezone.datetime.fromisoformat(start_date).date()
        end = timezone.datetime.fromisoformat(end_date).date()
    except Exception:
        end = timezone.now().date()
        start = end - timezone.timedelta(days=30)
    report = FinancialReportGenerator.generate_cash_flow(start, end)
    report.generated_by = request.user
    report.save(update_fields=['generated_by'])
    pdf_bytes = FinancialReportGenerator.generate_cash_flow_pdf(report)
    if pdf_bytes:
        filename = f"cash_flow_{start}_{end}.pdf"
        report.report_file.save(filename, ContentFile(pdf_bytes), save=True)
        resp = HttpResponse(pdf_bytes, content_type='application/pdf')
        resp['Content-Disposition'] = f'attachment; filename="{filename}"'
        messages.success(request, 'Cash flow PDF generated.')
        return resp
    messages.warning(request, 'PDF generation library not installed. Export CSV instead.')
    return redirect(f"{request.build_absolute_uri('/staff/ledger/export/')}?type=cash_flow&start_date={start}&end_date={end}")
@login_required(login_url='/staff/login/')
@user_passes_test(is_staff_user, login_url='/staff/login/')
def pending_products(request):
    """List of products pending approval"""
    from vendors.models import Vendor, VendorStore
    
    if not (
        request.user.has_permission('manage_inventory')
        or request.user.has_permission('manage_products')
        or getattr(request.user, "is_admin", False)
    ):
        messages.error(request, 'You do not have permission to review products.')
        return redirect('staff:dashboard')
    
    pending = Product.objects.filter(
        approval_status='PENDING'
    ).select_related('vendor', 'category', 'store').order_by('-created_at')
    
    search = request.GET.get('search') or ''
    category_id = request.GET.get('category') or ''
    store_id = request.GET.get('store') or ''
    product_id = request.GET.get('product') or ''
    
    if search:
        pending = pending.filter(name__icontains=search)
    if category_id:
        try:
            pending = pending.filter(category_id=int(category_id))
        except Exception:
            pass
    if store_id:
        try:
            pending = pending.filter(store_id=int(store_id))
        except Exception:
            pass
    if product_id:
        try:
            pending = pending.filter(id=int(product_id))
        except Exception:
            pass
    
    categories = Category.objects.all().order_by('name')
    stores = VendorStore.objects.filter(is_active=True).order_by('name')
    product_options = Product.objects.filter(approval_status='PENDING').values('id','name','category_id').order_by('name')
    
    context = {
        'pending_products': pending,
        'total_pending': pending.count(),
        'categories': categories,
        'stores': stores,
        'selected_category': category_id,
        'selected_store': store_id,
        'selected_product': product_id,
        'product_options': product_options,
        'search_query': search,
    }
    
    return render(request, 'staff/pending_products.html', context)


@login_required(login_url='/staff/login/')
@user_passes_test(is_staff_user, login_url='/staff/login/')
def review_product(request, product_id):
    """Review and approve/reject a product"""
    from vendors.models import Vendor
    from django.shortcuts import get_object_or_404
    
    if not (
        request.user.has_permission('manage_inventory')
        or request.user.has_permission('manage_products')
        or getattr(request.user, "is_admin", False)
    ):
        messages.error(request, 'You do not have permission to review products.')
        return redirect('staff:dashboard')
    
    product = get_object_or_404(
        Product.objects.select_related('category', 'vendor', 'store').prefetch_related('images', 'variations'),
        id=product_id
    )
    
    if request.method == 'POST':
        action = request.POST.get('action')
        
        if action == 'approve':
            if (not product.featured_image) and (not product.images.exists()):
                messages.error(request, 'Product must have at least one image before approval.')
                return redirect('staff:review_product', product_id=product_id)
            product.approval_status = 'APPROVED'
            product.is_active = True
            product.reviewed_by = request.user
            product.reviewed_at = timezone.now()
            product.rejection_reason = ''
            product.save()
            messages.success(request, f'Product "{product.name}" approved successfully!')
            if product.vendor and product.vendor.business_email:
                try:
                    send_mail(
                        subject='Your product has been approved',
                        message=f'Hello {product.vendor.store_name},\n\nYour product "{product.name}" has been approved and is now live.\n\nRegards,\nAiBiMagics Staff',
                        from_email=settings.DEFAULT_FROM_EMAIL,
                        recipient_list=[product.vendor.business_email],
                        fail_silently=True,
                    )
                except Exception:
                    pass
            
        elif action == 'reject':
            reason = request.POST.get('rejection_reason', '')
            if not reason:
                messages.error(request, 'Please provide a reason for rejection')
                return redirect('staff:review_product', product_id=product_id)
            
            product.approval_status = 'REJECTED'
            product.is_active = False
            product.reviewed_by = request.user
            product.reviewed_at = timezone.now()
            product.rejection_reason = reason
            product.save()
            messages.success(request, f'Product "{product.name}" rejected')
            if product.vendor and product.vendor.business_email:
                try:
                    send_mail(
                        subject='Your product submission was rejected',
                        message=f'Hello {product.vendor.store_name},\n\nYour product "{product.name}" was rejected.\nReason: {reason}\n\nYou can update the product and resubmit for review.\n\nRegards,\nAiBiMagics Staff',
                        from_email=settings.DEFAULT_FROM_EMAIL,
                        recipient_list=[product.vendor.business_email],
                        fail_silently=True,
                    )
                except Exception:
                    pass
        elif action == 'update':
            if product.approval_status == 'APPROVED':
                messages.error(request, 'Approved products are view-only.')
                return redirect('staff:review_product', product_id=product_id)
            try:
                details_val = (request.POST.get('details', '') or '').strip()
                if not details_val:
                    messages.error(request, 'Details are required')
                    raise ValueError('Details are required')
                product.short_description = request.POST.get('short_description') or product.short_description
                product.description = request.POST.get('description') or product.description
                product.details = details_val or product.details
                product.reviewed_by = request.user
                product.reviewed_at = timezone.now()
                product.save()
                messages.success(request, 'Product updated successfully')
            except Exception as e:
                messages.error(request, f'Error updating product: {str(e)}')
            return redirect('staff:review_product', product_id=product_id)
        
        return redirect('staff:pending_products')
    
    categories = Category.objects.all().order_by('name')
    context = {
        'product': product,
        'categories': categories,
    }
    
    return render(request, 'staff/review_product.html', context)


@login_required(login_url='/staff/login/')
@user_passes_test(is_staff_user, login_url='/staff/login/')
def staff_profile(request):
    """Staff Profile (non-KYC settings)"""
    if request.method == 'POST':
        user = request.user
        if user.kyc_approved or user.is_verified:
            messages.error(request, 'Profile is locked after approval. Contact admin for changes.')
            return redirect('staff:profile')
        user.first_name = request.POST.get('first_name', user.first_name)
        user.last_name = request.POST.get('last_name', user.last_name)
        user.phone = request.POST.get('phone', user.phone)
        user.save()
        messages.success(request, 'Profile updated successfully!')
        return redirect('staff:profile')
    
    return render(request, 'staff/profile.html', {'is_kyc_page': False})


@login_required(login_url='/staff/login/')
@user_passes_test(is_staff_user, login_url='/staff/login/')
def staff_kyc(request):
    """Staff KYC Submission (separate page)"""
    user = request.user
    if request.method == 'POST':
        if user.kyc_approved:
            messages.error(request, 'KYC is already approved. Contact admin for changes.')
            return redirect('staff:kyc')
        user.aadhaar_no = request.POST.get('aadhaar_no', user.aadhaar_no)
        user.gst_no = request.POST.get('gst_no', user.gst_no)
        if request.FILES.get('consent_form'):
            f = request.FILES['consent_form']
            if not _scan_file_placeholder(f):
                messages.error(request, 'File contains malicious content.')
                return redirect('staff:kyc')
            user.consent_form = f
        if request.FILES.get('kyc_photo'):
            f = request.FILES['kyc_photo']
            if not _scan_file_placeholder(f):
                messages.error(request, 'File contains malicious content.')
                return redirect('staff:kyc')
            user.kyc_photo = f
        if request.FILES.get('kyc_address_proof'):
            f = request.FILES['kyc_address_proof']
            if not _scan_file_placeholder(f):
                messages.error(request, 'File contains malicious content.')
                return redirect('staff:kyc')
            user.kyc_address_proof = f
        if request.FILES.get('self_photo'):
            f = request.FILES['self_photo']
            if not _scan_file_placeholder(f):
                messages.error(request, 'File contains malicious content.')
                return redirect('staff:kyc')
            user.profile_picture = f
        submitting_kyc = request.POST.get('kyc_submitted') == 'on'
        errors = []
        if submitting_kyc:
            aadhaar_clean = (user.aadhaar_no or '').strip()
            if not aadhaar_clean:
                errors.append('Aadhaar number is required for KYC submission.')
            if not user.consent_form:
                errors.append('Consent form is required for KYC submission.')
            if not user.kyc_photo:
                errors.append('Aadhaar card image is required for KYC submission.')
            if not user.kyc_address_proof:
                errors.append('Current address proof image is required for KYC submission.')
            if not user.profile_picture:
                errors.append('Self photo is required for KYC submission.')
            if errors:
                for msg_text in errors:
                    messages.error(request, msg_text)
                user.save()
                return redirect('staff:kyc')
            user.kyc_submitted = True
        user.save()
        messages.success(request, 'KYC details submitted successfully!')
        return redirect('staff:kyc')
    
    return render(request, 'staff/profile.html', {'is_kyc_page': True})


@login_required(login_url='/staff/login/')
@user_passes_test(is_staff_user, login_url='/staff/login/')
def staff_consent_form(request):
    user = request.user
    try:
        from reportlab.lib.pagesizes import A4
        from reportlab.pdfgen import canvas
        from reportlab.lib.units import cm
    except Exception:
        return render(request, 'staff/consent_form.html')
    buffer = BytesIO()
    pdf = canvas.Canvas(buffer, pagesize=A4)
    width, height = A4
    pdf.saveState()
    pdf.setFont("Helvetica-Bold", 60)
    pdf.setFillGray(0.9)
    pdf.translate(width / 2, height / 2)
    pdf.rotate(45)
    pdf.drawCentredString(0, 0, "AiBiMagics")
    pdf.restoreState()
    y = height - 2 * cm
    pdf.setFont("Helvetica-Bold", 16)
    pdf.drawCentredString(width / 2, y, "Staff KYC Consent Form")
    y -= 0.8 * cm
    pdf.setFont("Helvetica", 12)
    pdf.drawCentredString(width / 2, y, "AiBiMagics Platform")
    y -= 1.4 * cm
    pdf.setFont("Helvetica", 11)
    left = 2 * cm
    label_width = 4.5 * cm
    pdf.drawString(left, y, "Staff Name:")
    pdf.line(left + label_width, y - 0.1 * cm, width - 2 * cm, y - 0.1 * cm)
    y -= 0.8 * cm
    pdf.drawString(left, y, "Staff Email:")
    pdf.line(left + label_width, y - 0.1 * cm, width - 2 * cm, y - 0.1 * cm)
    y -= 0.8 * cm
    pdf.drawString(left, y, "Phone Number:")
    pdf.line(left + label_width, y - 0.1 * cm, width - 2 * cm, y - 0.1 * cm)
    y -= 0.8 * cm
    pdf.drawString(left, y, "Aadhaar Number:")
    pdf.line(left + label_width, y - 0.1 * cm, width - 2 * cm, y - 0.1 * cm)
    y -= 0.8 * cm
    pdf.drawString(left, y, "Current Address:")
    pdf.line(left + label_width, y - 0.1 * cm, width - 2 * cm, y - 0.1 * cm)
    y -= 0.8 * cm
    pdf.line(left + label_width, y - 0.1 * cm, width - 2 * cm, y - 0.1 * cm)
    y -= 0.8 * cm
    pdf.line(left + label_width, y - 0.1 * cm, width - 2 * cm, y - 0.1 * cm)
    photo_box_w = 3 * cm
    photo_box_h = 4 * cm
    photo_x = width - (photo_box_w + 2 * cm)
    photo_y = height - 5 * cm
    pdf.rect(photo_x, photo_y, photo_box_w, photo_box_h)
    pdf.setFont("Helvetica", 9)
    pdf.drawCentredString(photo_x + photo_box_w / 2, photo_y - 0.4 * cm, "Paste Recent Passport Size Photo")
    y -= 1.4 * cm
    text = pdf.beginText()
    text.setTextOrigin(left, y)
    text.setFont("Helvetica", 11)
    paragraphs = [
        "I, the undersigned staff member, hereby consent and agree that:",
        "",
        "1. I am voluntarily submitting my KYC documents (Aadhaar card, address proof and",
        "   supporting files) to AiBiMagics for internal verification and compliance purposes",
        "   related to my staff role.",
        "",
        "2. AiBiMagics may securely store and process my KYC information only for legitimate",
        "   business, compliance and audit requirements, and will not share it with third",
        "   parties except as required by law.",
        "",
        "3. I confirm that all information and documents submitted by me are true, correct",
        "   and up to date to the best of my knowledge.",
        "",
        "4. I understand that providing false or misleading information may result in",
        "   suspension or termination of my staff access to the platform.",
    ]
    for line in paragraphs:
        text.textLine(line)
    pdf.drawText(text)
    y = 4.2 * cm
    pdf.setFont("Helvetica", 11)
    pdf.drawString(left, y, "Date:")
    pdf.line(left + 1.7 * cm, y - 0.1 * cm, width / 2 - cm, y - 0.1 * cm)
    sig_y = 2.4 * cm
    block_width = (width - 4 * cm) / 2
    witness_y = sig_y + 1.1 * cm
    pdf.line(left, witness_y, left + block_width, witness_y)
    pdf.drawString(left, witness_y - 0.6 * cm, "Witness Signature")
    right_witness_x = left + block_width + 1.5 * cm
    pdf.line(right_witness_x, witness_y, right_witness_x + block_width, witness_y)
    pdf.drawString(right_witness_x, witness_y - 0.6 * cm, "Witness Name")
    pdf.line(left, sig_y, left + block_width, sig_y)
    pdf.drawString(left, sig_y - 0.6 * cm, "Staff Signature")
    right_x = left + block_width + 1.5 * cm
    pdf.line(right_x, sig_y, right_x + block_width, sig_y)
    pdf.drawString(right_x, sig_y - 0.6 * cm, "Staff Name")
    pdf.showPage()
    pdf.save()
    pdf_bytes = buffer.getvalue()
    buffer.close()
    response = HttpResponse(pdf_bytes, content_type="application/pdf")
    response["Content-Disposition"] = 'attachment; filename="staff_kyc_consent_form.pdf"'
    return response

@login_required(login_url='/staff/login/')
@user_passes_test(is_staff_user, login_url='/staff/login/')
def staff_trigger_vendor_payout(request, vendor_id):
    user = request.user
    if not (getattr(user, 'is_admin', False) or user.role in [User.Role.STAFF_ADMIN, User.Role.ACCOUNTANT] or user.has_permission('manage_finance')):
        messages.error(request, 'You do not have permission to trigger payouts.')
        return redirect('staff:dashboard')
    try:
        from vendors.models import Vendor, VendorCommission, VendorPayout
    except Exception:
        messages.error(request, 'Vendor module not available.')
        return redirect('staff:dashboard')
    try:
        vendor = Vendor.objects.get(id=int(vendor_id))
    except Exception:
        messages.error(request, 'Vendor not found.')
        return redirect('staff:manage_vendors')
    unpaid_commissions = VendorCommission.objects.filter(vendor=vendor, is_paid=False)
    amount = unpaid_commissions.aggregate(total=Sum('vendor_payout'))['total'] or Decimal('0')
    if amount <= 0:
        messages.error(request, 'No unpaid commissions to payout.')
        return redirect('staff:vendor_detail', vendor_id=vendor_id)
    from payments.utils import BankAPIClient
    client = BankAPIClient()
    reference = f"VENDOR-PAYOUT-{vendor.id}-{timezone.now().strftime('%Y%m%d%H%M%S')}"
    resp = client.initiate_transfer(
        vendor.bank_account_number,
        vendor.bank_routing_number,
        vendor.bank_account_name,
        amount,
        reference
    )
    status = 'PROCESSING'
    tx_ref = ''
    if isinstance(resp, dict) and resp.get('status_code') and int(resp.get('status_code')) in range(200, 300):
        status = 'COMPLETED'
        tx_ref = str(resp.get('body', {}).get('transaction_id', reference))
    elif resp.get('success') is False:
        status = 'FAILED'
    payout = VendorPayout.objects.create(
        vendor=vendor,
        amount=amount,
        status=status,
        transaction_reference=tx_ref or reference,
        processed_at=timezone.now()
    )
    payout.commissions.add(*list(unpaid_commissions))
    if status == 'COMPLETED':
        for c in unpaid_commissions:
            c.is_paid = True
            c.paid_at = timezone.now()
            c.payout_reference = payout.transaction_reference
            c.save(update_fields=['is_paid', 'paid_at', 'payout_reference'])
        payout.completed_at = timezone.now()
        payout.save(update_fields=['completed_at'])
        messages.success(request, f'Payout initiated and marked completed for Rs.{amount}.')
    elif status == 'FAILED':
        messages.error(request, 'Payout initiation failed.')
    else:
        messages.info(request, 'Payout initiated and is processing.')
    return redirect('staff:vendor_detail', vendor_id=vendor_id)
