from django.shortcuts import render, get_object_or_404, redirect
from django.http import JsonResponse
from django.db import transaction
from django.db.models import Sum, F
from django.utils import timezone
from django.contrib import messages
from django.contrib.auth import login, logout, authenticate
from django.contrib.auth.forms import AuthenticationForm, UserCreationForm
from django.contrib.auth.decorators import login_required, user_passes_test
from django.contrib.auth.models import User
from .models import Ingredient, MenuItem, MenuItemIngredient, Order, OrderItem, UserProfile
import json

def is_manager(user):
    return user.is_authenticated and hasattr(user, 'profile') and user.profile.role == 'manager'

def is_cashier(user):
    return user.is_authenticated and hasattr(user, 'profile') and user.profile.role == 'cashier'

def manager_required(view_func):
    return user_passes_test(is_manager, login_url='login')(view_func)

def cashier_or_manager_required(view_func):
    return user_passes_test(lambda u: is_manager(u) or is_cashier(u), login_url='login')(view_func)

def login_view(request):
    if request.method == 'POST':
        form = AuthenticationForm(request, data=request.POST)
        if form.is_valid():
            user = form.get_user()
            login(request, user)
            if is_manager(user):
                return redirect('dashboard')
            return redirect('pos')
    else:
        form = AuthenticationForm()
    return render(request, 'core/login.html', {'form': form})

def logout_view(request):
    logout(request)
    return redirect('login')

def home(request):
    """Redirect home to login or dashboard/pos based on role."""
    if request.user.is_authenticated:
        if is_manager(request.user):
            return redirect('dashboard')
        return redirect('pos')
    return render(request, "core/index.html")

@cashier_or_manager_required
def pos_view(request):
    """Cashier POS interface."""
    menu_items = MenuItem.objects.filter(is_active=True)
    return render(request, "core/pos.html", {"menu_items": menu_items})

@cashier_or_manager_required
def create_order(request):
    """Handle order creation and stock deduction."""
    if request.method == "POST":
        try:
            data = json.loads(request.body)
            cart = data.get("cart", [])
            notes = data.get("notes", "")

            if not cart:
                return JsonResponse({"success": False, "error": "Cart is empty"}, status=400)

            with transaction.atomic():
                order = Order.objects.create(customer_notes=notes)
                total_price = 0

                for item in cart:
                    menu_item = get_object_or_404(MenuItem, id=item["id"])
                    quantity = int(item["quantity"])
                    
                    # Deduct stock
                    for recipe_item in menu_item.ingredients.all():
                        required_qty = recipe_item.quantity_required * quantity
                        ingredient = recipe_item.ingredient
                        if ingredient.stock_quantity < required_qty:
                            raise Exception(f"Insufficient stock for {ingredient.name}")
                        
                        ingredient.stock_quantity = F('stock_quantity') - required_qty
                        ingredient.save()

                    # Create OrderItem
                    OrderItem.objects.create(
                        order=order,
                        menu_item=menu_item,
                        quantity=quantity,
                        price_at_order=menu_item.price
                    )
                    total_price += menu_item.price * quantity

                order.total_price = total_price
                order.save()

            return JsonResponse({"success": True, "order_number": order.order_number})
        except Exception as e:
            return JsonResponse({"success": False, "error": str(e)}, status=400)
    return JsonResponse({"success": False, "error": "Invalid request"}, status=405)

@cashier_or_manager_required
def receipt_view(request, order_number):
    """Printable receipt view."""
    order = get_object_or_404(Order, order_number=order_number)
    return render(request, "core/receipt.html", {"order": order})

@manager_required
def dashboard_view(request):
    """Manager dashboard for stock and reports."""
    ingredients = Ingredient.objects.all()
    # Summary of last 30 orders
    orders = Order.objects.prefetch_related('items__menu_item').order_by('-created_at')[:50]
    total_sales = Order.objects.aggregate(Sum('total_price'))['total_price__sum'] or 0
    
    return render(request, "core/dashboard.html", {
        "ingredients": ingredients,
        "orders": orders,
        "total_sales": total_sales,
    })

@manager_required
def manage_users(request):
    """Manager only: Create and view accounts."""
    users = User.objects.all().select_related('profile')
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        role = request.POST.get('role')
        
        if username and password and role:
            if User.objects.filter(username=username).exists():
                messages.error(request, f"User {username} already exists.")
            else:
                user = User.objects.create_user(username=username, password=password)
                profile, created = UserProfile.objects.get_or_create(user=user)
                profile.role = role
                profile.save()
                messages.success(request, f"User {username} created as {role}.")
                return redirect('manage_users')
        else:
            messages.error(request, "Please fill all fields.")

    return render(request, 'core/user_management.html', {'users': users})

@manager_required
def delete_user(request, user_id):
    """Manager only: Delete a user account."""
    if request.user.id == user_id:
        messages.error(request, "You cannot delete your own account.")
        return redirect('manage_users')
    
    user = get_object_or_404(User, id=user_id)
    username = user.username
    user.delete()
    messages.success(request, f"User {username} has been deleted.")
    return redirect('manage_users')

@manager_required
def manage_ingredients(request):
    """Manager only: View and add ingredients."""
    if request.method == 'POST':
        name = request.POST.get('name')
        stock_quantity = request.POST.get('stock_quantity', 0)
        unit = request.POST.get('unit', 'grams')
        
        if name:
            if Ingredient.objects.filter(name__iexact=name).exists():
                messages.error(request, f"Ingredient '{name}' already exists.")
            else:
                Ingredient.objects.create(
                    name=name,
                    stock_quantity=stock_quantity,
                    unit=unit
                )
                messages.success(request, f"Ingredient '{name}' added successfully.")
        else:
            messages.error(request, "Ingredient name is required.")
        return redirect('dashboard')
    
    return redirect('dashboard')

@manager_required
def manage_menu(request):
    """Manager only: View and create menu items."""
    menu_items = MenuItem.objects.all()
    ingredients = Ingredient.objects.all()
    
    if request.method == 'POST':
        name = request.POST.get('name')
        price = request.POST.get('price')
        description = request.POST.get('description', '')
        image_url = request.POST.get('image_url', '')
        is_active = request.POST.get('is_active') == 'on'
        
        # Handle ingredient IDs and quantities from the form
        ingredient_ids = request.POST.getlist('ingredients')
        quantities = request.POST.getlist('quantities')

        if name and price:
            try:
                with transaction.atomic():
                    menu_item = MenuItem.objects.create(
                        name=name,
                        price=price,
                        description=description,
                        image_url=image_url,
                        is_active=is_active
                    )
                    
                    # Add ingredients if provided
                    for i_id, qty in zip(ingredient_ids, quantities):
                        if i_id and qty and float(qty) > 0:
                            ingredient = get_object_or_404(Ingredient, id=i_id)
                            MenuItemIngredient.objects.create(
                                menu_item=menu_item,
                                ingredient=ingredient,
                                quantity_required=qty
                            )
                            
                    messages.success(request, f"Menu item '{name}' created successfully.")
                    return redirect('manage_menu')
            except Exception as e:
                messages.error(request, f"Error creating menu item: {str(e)}")
        else:
            messages.error(request, "Name and price are required.")
            
    return render(request, 'core/menu_management.html', {
        'menu_items': menu_items,
        'ingredients': ingredients
    })

@manager_required
def edit_menu_item(request, pk):
    """Manager only: Edit an existing menu item."""
    menu_item = get_object_or_404(MenuItem, pk=pk)
    ingredients = Ingredient.objects.all()
    
    if request.method == 'POST':
        menu_item.name = request.POST.get('name')
        menu_item.price = request.POST.get('price')
        menu_item.description = request.POST.get('description', '')
        menu_item.image_url = request.POST.get('image_url', '')
        menu_item.is_active = request.POST.get('is_active') == 'on'
        
        ingredient_ids = request.POST.getlist('ingredients')
        quantities = request.POST.getlist('quantities')
        
        if menu_item.name and menu_item.price:
            try:
                with transaction.atomic():
                    menu_item.save()
                    
                    # Update ingredients: Clear existing and re-add
                    menu_item.ingredients.all().delete()
                    for i_id, qty in zip(ingredient_ids, quantities):
                        if i_id and qty and float(qty) > 0:
                            ingredient = get_object_or_404(Ingredient, id=i_id)
                            MenuItemIngredient.objects.create(
                                menu_item=menu_item,
                                ingredient=ingredient,
                                quantity_required=qty
                            )
                            
                    messages.success(request, f"Menu item '{menu_item.name}' updated successfully.")
                    return redirect('manage_menu')
            except Exception as e:
                messages.error(request, f"Error updating menu item: {str(e)}")
        else:
            messages.error(request, "Name and price are required.")
            
    return render(request, 'core/edit_menu_item.html', {
        'menu_item': menu_item,
        'ingredients': ingredients,
        'current_ingredients': menu_item.ingredients.all()
    })

@manager_required
def toggle_menu_item_status(request, pk):
    """Manager only: Toggle menu item active/inactive status."""
    menu_item = get_object_or_404(MenuItem, pk=pk)
    menu_item.is_active = not menu_item.is_active
    menu_item.save()
    status = "activated" if menu_item.is_active else "deactivated"
    messages.success(request, f"Menu item '{menu_item.name}' {status}.")
    return redirect('manage_menu')
