"""SKEVER Portal V1 — additive order workflow views. No schema changes."""
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.shortcuts import get_object_or_404, redirect
from django.views.decorators.http import require_POST

from .models import AuditEvent, Order


def _require_staff_permission(request, permission_codename):
    user = request.user
    if not user.is_authenticated or not user.is_active or not (user.is_staff or user.is_superuser):
        raise PermissionDenied("Active portal staff access is required.")
    if not user.has_perm(f"core.{permission_codename}"):
        raise PermissionDenied("You do not have permission to perform this action.")


def _audit_order_action(actor, order, action, description, metadata=None):
    AuditEvent.objects.create(
        actor=actor,
        action=action,
        entity_type="Order",
        entity_id=str(order.pk),
        description=description,
        metadata=metadata or {},
    )


@login_required
@require_POST
def order_accept(request, order_id):
    _require_staff_permission(request, "skv_accept_orders")
    with transaction.atomic():
        order = get_object_or_404(Order.objects.select_for_update(), pk=order_id)
        if order.status != Order.Status.NEW:
            messages.error(request, f"Order {order.order_number} cannot be accepted from its current status.")
            return redirect("dashboard")
        previous_status = order.status
        order.status = Order.Status.ACCEPTED
        order.save(update_fields=["status", "updated_at"])
        _audit_order_action(request.user, order, "order_accepted", f"Accepted order {order.order_number}.", {"previous_status": previous_status, "new_status": order.status})
    messages.success(request, f"Order {order.order_number} accepted.")
    return redirect("dashboard")


@login_required
@require_POST
def order_hold(request, order_id):
    _require_staff_permission(request, "skv_hold_orders")
    with transaction.atomic():
        order = get_object_or_404(Order.objects.select_for_update(), pk=order_id)
        if order.status not in {Order.Status.NEW, Order.Status.ACCEPTED}:
            messages.error(request, f"Order {order.order_number} cannot be placed on hold from its current status.")
            return redirect("dashboard")
        previous_status = order.status
        order.status = Order.Status.ON_HOLD
        order.save(update_fields=["status", "updated_at"])
        _audit_order_action(request.user, order, "order_put_on_hold", f"Placed order {order.order_number} on hold.", {"previous_status": previous_status, "new_status": order.status})
    messages.success(request, f"Order {order.order_number} placed on hold.")
    return redirect("dashboard")


@login_required
@require_POST
def order_decline(request, order_id):
    _require_staff_permission(request, "skv_decline_orders")
    reason = (request.POST.get("reason") or "").strip()
    if not reason:
        messages.error(request, "A decline reason is required.")
        return redirect("dashboard")
    if len(reason) > 10000:
        messages.error(request, "The decline reason is too long.")
        return redirect("dashboard")
    with transaction.atomic():
        order = get_object_or_404(Order.objects.select_for_update(), pk=order_id)
        if order.status not in {Order.Status.NEW, Order.Status.ACCEPTED, Order.Status.ON_HOLD}:
            messages.error(request, f"Order {order.order_number} cannot be declined from its current status.")
            return redirect("dashboard")
        previous_status = order.status
        order.status = Order.Status.DECLINED
        order.decline_reason = reason
        order.save(update_fields=["status", "decline_reason", "updated_at"])
        _audit_order_action(request.user, order, "order_declined", f"Declined order {order.order_number}.", {"previous_status": previous_status, "new_status": order.status, "reason": reason})
    messages.success(request, f"Order {order.order_number} declined.")
    return redirect("dashboard")


@login_required
@require_POST
def order_start_processing(request, order_id):
    _require_staff_permission(request, "skv_accept_orders")
    with transaction.atomic():
        order = get_object_or_404(Order.objects.select_for_update(), pk=order_id)
        if order.status != Order.Status.ACCEPTED:
            messages.error(request, f"Order {order.order_number} must be accepted before processing.")
            return redirect("dashboard")
        previous_status = order.status
        order.status = Order.Status.PROCESSING
        order.save(update_fields=["status", "updated_at"])
        _audit_order_action(request.user, order, "order_processing_started", f"Moved order {order.order_number} into processing.", {"previous_status": previous_status, "new_status": order.status})
    messages.success(request, f"Order {order.order_number} moved to processing.")
    return redirect("dashboard")
