from datetime import timezone
from django.forms import modelformset_factory
from django.http import JsonResponse
from django.shortcuts import render, redirect, get_object_or_404
from django.core.paginator import Paginator
from django.db.models import Q, Sum, F, DecimalField
from decimal import Decimal
from django.db.models.functions import Coalesce

from accounting.models import JournalEntry, Transaction, Account
from .models import MaterialConsumption, Product, StockMovement, Warehouse, ProductCategory, MaterialType
from .forms import MaterialConsumptionForm, MaterialConsumptionItemFormSet, ProductForm, StockMovementForm

from django.contrib import messages
from django.db import transaction

# Create your views here.
# Add Product
def add_product(request):
    if request.method == 'POST':
        form = ProductForm(request.POST, request.FILES)
        if form.is_valid():
            product = form.save(commit=False)
            product.is_active = True  # Default to active
            # product.created_by = request.user
            product.save()
            messages.success(request, 'Product added successfully!')
            return redirect('product_list')
        else:
            print(form.errors)  # Debugging line to check form errors
            messages.error(request, 'Please correct the errors below.')
    else:
        form = ProductForm(initial={'is_active': True})  # Default to active
    
    context = {
        'form': form,
        'title': 'Add New Product',
    }
    return render(request, 'products/add_product.html', context)

# ✅ Edit Product View
def edit_product(request, pk):
    product = get_object_or_404(Product, pk=pk)

    if request.method == "POST":
        form = ProductForm(request.POST, request.FILES, instance=product)
        if form.is_valid():
            form.save()
            messages.success(request, "Product updated successfully.")
            return redirect("product_list")
        else:
            messages.error(request, "Please correct the errors below.")
    else:
        form = ProductForm(instance=product)

    context = {
        "form": form,
        "product": product,
        "title": "Edit Product",
    }

    return render(request, "products/edit_product.html", context)

# Delete Product View
def delete_product(request, pk):
    product = get_object_or_404(Product, pk=pk)
    if request.method == "POST":
        product.delete()
        return redirect("product_list")

    return render(request, "products/delete_product.html", {"product": product})

# @login_required
def product_list(request):
    # Get search query
    search_query = request.GET.get('search', '')
    
    # Get filter parameters
    material_filter = request.GET.get('material')
    # status_filter = request.GET.get('status')
    
    # Base queryset
    products = Product.objects.all().select_related( 'material_type').order_by('name')
    
    # Apply filters
    if search_query:
        products = products.filter(
            Q(code__icontains=search_query) |
            Q(name__icontains=search_query) |
            Q(description__icontains=search_query)
        )
    
  
    if material_filter:
        products = products.filter(material_type_id=material_filter)
    
     # Calculate current_stock for each product in Python
    for product in products:
        product.current_stock_value = product.current_stock
         # ➕ Average Purchase Price from Stock IN
        purchase_data = StockMovement.objects.filter(
            product=product,
            movement_type='IN',
            purchase_price__isnull=False
        ).aggregate(
            total_price=Sum(F('purchase_price') * F('quantity'), output_field=DecimalField()),
            total_qty=Sum('quantity')
        )
        if purchase_data['total_qty']:
            product.avg_purchase_price = round(purchase_data['total_price'] / purchase_data['total_qty'], 0)
        else:
            product.avg_purchase_price = 0

        # ➖ Average Sales Price from Stock OUT
        sales_data = StockMovement.objects.filter(
            product=product,
            movement_type='OUT',
            sale_price__isnull=False
        ).aggregate(
            total_price=Sum(F('sale_price') * F('quantity'), output_field=DecimalField()),
            total_qty=Sum('quantity')
        )
        if sales_data['total_qty']:
            product.avg_sales_price = round(sales_data['total_price'] / sales_data['total_qty'], 0)
        else:
            product.avg_sales_price = 0
        
        print(product.avg_sales_price, product.avg_purchase_price)
    
    # Pagination
    paginator = Paginator(products, 25)  # Show 25 products per page
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    
    # Get filter options
    categories = ProductCategory.objects.all()
    material_types = MaterialType.objects.all()
    
    
    return render(request, 'products/product_list.html', {
        'page_obj': page_obj,
        'categories': categories,
        'material_types': material_types,
        'search_query': search_query,
        'selected_material': material_filter,
        # 'selected_status': status_filter,
    })



def stock_dashboard(request):
    # Low stock alert
    products = Product.objects.annotate(
        current_stock=Sum('stock_movements__quantity')
    ).filter(is_active=True)
    
    low_stock = products.filter(current_stock__lte=F('min_stock_level'))
    
    # Recent movements
    recent_movements = StockMovement.objects.select_related('product', 'warehouse', 'user')[:10]
    
    return render(request, 'products/stock_dashboard.html', {
        'low_stock': low_stock,
        'recent_movements': recent_movements,
    })


# @login_required
def stock_movement_list(request):
    movements = StockMovement.objects.select_related(
        'product', 'warehouse', 'user'
    ).order_by('-date')
    
    return render(request, 'products/stock_movement_list.html', {
        'movements': movements,
    })

# @login_required
def add_stock_movement(request):
    if request.method == 'POST':
        form = StockMovementForm(request.POST, user=request.user)
        if form.is_valid():
            movement = form.save(commit=False)
            movement.user = request.user
            movement.save()
            return redirect('stock_movement_list')
    else:
        form = StockMovementForm(user=request.user)
    
    return render(request, 'products/stock_movement_form.html', {
        'form': form,
        'title': 'Add Stock Movement',
    })

def get_latest_purchase_price(product):
    latest_stock_in = StockMovement.objects.filter(
        product=product,
        movement_type='IN'
    ).order_by('-date').first()
    return latest_stock_in.purchase_price if latest_stock_in else 0


@transaction.atomic
def create_material_consumption(request):
    if request.method == 'POST':
        form = MaterialConsumptionForm(request.POST)
        formset = MaterialConsumptionItemFormSet(request.POST)
        print ("testing")  # Debugging line to check form errors
        if form.is_valid() and formset.is_valid():
            consumption = form.save(commit=False)
            consumption.created_by = request.user
            consumption.save()
            formset.instance = consumption
            formset.save()

            # Call your stock update and journal entry creation function here
            # handle_material_consumption_post_save(consumption)
            warehouse = form.cleaned_data['warehouse']
            handle_material_consumption_post_save(consumption, warehouse)
            
            messages.success(request, "Material consumption recorded successfully.")
            return redirect('material_consumption_list')  # Create this view later
    else:
        form = MaterialConsumptionForm()
        formset = MaterialConsumptionItemFormSet()

    return render(request, 'products/material_consumption.html', {
        'form': form,
        'formset': formset
    })


def handle_material_consumption_post_save(consumption, warehouse):
    # Create Journal Entry
    journal = JournalEntry.objects.create(
        date=consumption.date,
        description=f"Material consumed for project {consumption.project.project_title}",
        project=consumption.project
    )

    for item in consumption.items.all():
        total_cost = item.quantity * item.unit_price

        # 1. Record stock movement as OUT
        StockMovement.objects.create(
            product=item.product,
            warehouse=warehouse,  
            movement_type='OUT',
            quantity=item.quantity,
            purchase_price=item.unit_price,
            reference=f"Material Consumption #{consumption.id}",
            notes=f"Consumed for project {consumption.project.project_title}"
        )


        # 2. Create accounting transactions

        # Debit: Project Expense / WIP
        Transaction.objects.create(
            journal_entry=journal,
            account=get_account("Construction Expense"),  # or WIP
            debit=total_cost,
            credit=0,
            description=f"Material consumed for {item.product.name} in project {consumption.project.project_title}"
        )

        # Credit: Inventory
        Transaction.objects.create(
            journal_entry=journal,
            account=get_account("Inventory"),
            credit=total_cost,
            debit=0
        )


def get_account(name):
    return Account.objects.get(name=name)

def material_consumption_list(request):
    consumptions = MaterialConsumption.objects.select_related('project').order_by('-date')
    
    # Pagination
    paginator = Paginator(consumptions, 25)  # Show 25 consumptions per page
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    
    return render(request, 'products/material_consumption_list.html', {
        'page_obj': page_obj,
        'title': 'Material Consumption List',
        'consumptions': consumptions,
    })

def get_product_stock(request):
    product_id = request.GET.get('product_id')
    try:
        product = Product.objects.get(id=product_id)

        stock_in = StockMovement.objects.filter(product=product, movement_type='IN').aggregate(total=Sum('quantity'))['total'] or 0
        stock_out = StockMovement.objects.filter(product=product, movement_type='OUT').aggregate(total=Sum('quantity'))['total'] or 0
        adjustments = StockMovement.objects.filter(product=product, movement_type='ADJ').aggregate(total=Sum('quantity'))['total'] or 0
        transfers = StockMovement.objects.filter(product=product, movement_type='TRF').aggregate(total=Sum('quantity'))['total'] or 0

        available = stock_in + adjustments + transfers - stock_out

        return JsonResponse({'stock': float(available)})
    except Product.DoesNotExist:
        return JsonResponse({'stock': 0})


def material_consumption_detail(request, pk):
    consumption = get_object_or_404(MaterialConsumption, pk=pk)
    items = consumption.items.all()
    return render(request, 'products/material_consumption_detail.html', {
        'consumption': consumption,
        'items': items
    })