from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.core.exceptions import PermissionDenied
from django.db import transaction
from django.db.models import Sum
from django.shortcuts import get_object_or_404, redirect, render

from accounts.permissions import admin_required, any_authenticated
from core.project_utils import get_current_project
from flats.models import Flat
from sales.forms import FlatSaleForm, InstallmentForm
from sales.models import FlatSale, Installment


def _current_project(request):
    return get_current_project(request)


def _project_sale(pk, project):
    return get_object_or_404(FlatSale, pk=pk, flat__floor__building__project=project)


def _sync_flat_paid(sale):
    sale.flat.paid_amount = sale.total_received
    sale.flat.status = "sold"
    sale.flat.save(update_fields=["paid_amount", "status", "updated_at"])


@login_required
@any_authenticated
def sale_list(request):
    project = _current_project(request)
    sales = FlatSale.objects.filter(flat__floor__building__project=project).select_related("flat__floor__building") if project else FlatSale.objects.none()
    return render(request, "sales/sale_list.html", {"sales": sales, "project": project})


@login_required
@admin_required
def sale_create(request):
    project = _current_project(request)
    form = FlatSaleForm(request.POST or None, project=project)
    if request.method == "POST" and form.is_valid():
        with transaction.atomic():
            sale = form.save(commit=False)
            sale.created_by = request.user
            sale.updated_by = request.user
            sale.save()
            _sync_flat_paid(sale)
        messages.success(request, f"Sale for {sale.flat} was created and the unit was marked Sold.")
        return redirect("sales:sale_detail", pk=sale.pk)
    return render(request, "sales/sale_form.html", {"form": form, "project": project, "title": "New Flat Sale"})


@login_required
@admin_required
def sale_edit(request, pk):
    project = _current_project(request)
    sale = _project_sale(pk, project)
    form = FlatSaleForm(request.POST or None, instance=sale, project=project)
    if request.method == "POST" and form.is_valid():
        with transaction.atomic():
            sale = form.save(commit=False)
            sale.updated_by = request.user
            sale.save()
            _sync_flat_paid(sale)
        messages.success(request, "Flat sale updated successfully.")
        return redirect("sales:sale_detail", pk=sale.pk)
    return render(request, "sales/sale_form.html", {"form": form, "project": project, "title": "Edit Flat Sale", "sale": sale})


@login_required
@admin_required
def sale_delete(request, pk):
    project = _current_project(request)
    sale = _project_sale(pk, project)
    if request.method == "POST":
        flat = sale.flat
        sale.delete()
        flat.paid_amount = 0
        flat.status = "for_sale"
        flat.save(update_fields=["paid_amount", "status", "updated_at"])
        messages.success(request, "Sale deleted. The unit is available for sale again.")
        return redirect("sales:sale_list")
    return render(request, "sales/confirm_delete.html", {"object": sale, "project": project})


@login_required
@any_authenticated
def sale_detail(request, pk):
    project = _current_project(request)
    sale = _project_sale(pk, project)
    installments = sale.installments.all()
    return render(request, "sales/sale_detail.html", {"sale": sale, "installments": installments, "project": project})


@login_required
@admin_required
def installment_create(request, sale_pk):
    project = _current_project(request)
    sale = _project_sale(sale_pk, project)
    form = InstallmentForm(request.POST or None)
    if request.method == "POST" and form.is_valid():
        amount = form.cleaned_data["amount"]
        if amount <= 0:
            form.add_error("amount", "Amount must be greater than zero.")
        elif amount > sale.due_amount:
            form.add_error("amount", f"Payment cannot exceed the current due amount of ৳{sale.due_amount:,.2f}.")
        else:
            with transaction.atomic():
                installment = form.save(commit=False)
                installment.sale = sale
                installment.created_by = request.user
                installment.updated_by = request.user
                installment.save()
                _sync_flat_paid(sale)
            messages.success(request, "Installment/payment recorded successfully.")
            return redirect("sales:sale_detail", pk=sale.pk)
    return render(request, "sales/installment_form.html", {"form": form, "sale": sale, "project": project, "title": "Record Payment"})


@login_required
@admin_required
def installment_edit(request, pk):
    project = _current_project(request)
    installment = get_object_or_404(Installment, pk=pk, sale__flat__floor__building__project=project)
    sale = installment.sale
    old_amount = installment.amount
    form = InstallmentForm(request.POST or None, instance=installment)
    if request.method == "POST" and form.is_valid():
        new_amount = form.cleaned_data["amount"]
        available_due = sale.due_amount + old_amount
        if new_amount <= 0:
            form.add_error("amount", "Amount must be greater than zero.")
        elif new_amount > available_due:
            form.add_error("amount", f"Payment cannot exceed the available balance of ৳{available_due:,.2f}.")
        else:
            with transaction.atomic():
                installment = form.save(commit=False)
                installment.updated_by = request.user
                installment.save()
                _sync_flat_paid(sale)
            messages.success(request, "Payment updated successfully.")
            return redirect("sales:sale_detail", pk=sale.pk)
    return render(request, "sales/installment_form.html", {"form": form, "sale": sale, "project": project, "title": "Edit Payment", "installment": installment})


@login_required
@admin_required
def installment_delete(request, pk):
    project = _current_project(request)
    installment = get_object_or_404(Installment, pk=pk, sale__flat__floor__building__project=project)
    sale = installment.sale
    if request.method == "POST":
        installment.delete()
        _sync_flat_paid(sale)
        messages.success(request, "Payment deleted successfully.")
        return redirect("sales:sale_detail", pk=sale.pk)
    return render(request, "sales/confirm_installment_delete.html", {"object": installment, "sale": sale, "project": project})
