"""Trusted integration boundary: callers hold ServiceCase FOR UPDATE.

Quotation writers hold that same lock. No dependency locks are acquired here.
Authorization evidence commits/rolls back with its technical or physical write.
"""
from django.core.exceptions import ValidationError
from django.db.models import Sum
from .models import QuotationFamily, ServiceQuotation, CommercialWorkAuthorization


def customer_pay_approval_required(service_case):
    return QuotationFamily.objects.filter(service_case=service_case, approval_obligation=True).exists()


def require_commercial_authorization(*, service_case, actor, operation, repair_execution, action=None, spare_part=None, quantity=0):
    if not customer_pay_approval_required(service_case):
        return None
    quotation = ServiceQuotation.objects.filter(family__service_case=service_case, is_current=True, status="APPROVED").first()
    if quotation is None:
        raise ValidationError("Current commercial scope requires customer approval before performing work.")
    scope = {item["id"]:item for item in quotation.scope_snapshot}
    actions = [action] if action else list(repair_execution.actions.filter(is_active=True))
    for current in actions:
        item = scope.get(str(current.pk))
        if item is None or item["repair_action_id"] != str(current.repair_action_id) or item["note"] != current.note:
            raise ValidationError("Repair scope changed; submit and approve a new quotation revision.")
    if operation == "CONSUME":
        allowed = quotation.lines.filter(is_active=True, kind="PART", spare_part=spare_part).aggregate(n=Sum("quantity"))["n"] or 0
        used = CommercialWorkAuthorization.objects.filter(quotation__family=quotation.family_id,
            operation="CONSUME", spare_part=spare_part).aggregate(n=Sum("quantity"))["n"] or 0
        if used + quantity > allowed:
            raise ValidationError("Consumption exceeds this revision's approved part scope.")
    record = CommercialWorkAuthorization(quotation=quotation, actor=actor, operation=operation,
        repair_execution=repair_execution, repair_action=action, spare_part=spare_part, quantity=quantity)
    record._persist()
    return record
