"""ORM 通用辅助"""
from django.db.models import Subquery, OuterRef, Sum, Value, DecimalField
from django.db.models.functions import Coalesce


def inflight_sum(model, fk, submit_isnull_path, amount, *, max_digits=12, decimal_places=1):
    """未提交单据的"在途"聚合量(存量之外正在出入库/在制/在途交接的数量)。

    用关联标量子查询实现, 不与主表 JOIN, 因此可在同一个 queryset 上安全叠加
    多个不同多值关系的聚合而不会因笛卡尔积翻倍(Django 多聚合经典陷阱)。

    :param model: 明细模型, 如 MIOItem / Mlogb / Handoverb
    :param fk: 明细指向主表的外键名, 如 'mb' / 'wm_in' / 'wm'
    :param submit_isnull_path: 判定"未提交"的查询路径, 如 'mio__submit_time__isnull'
    :param amount: 参与求和的数量字段, 如 'count' / 'count_use'
    """
    return Coalesce(
        Subquery(
            model.objects
                 .filter(**{fk: OuterRef('pk'), submit_isnull_path: True})
                 .order_by()               # 清掉默认排序, 否则污染 GROUP BY
                 .values(fk)               # 按外键分组 -> 每个主键一行
                 .annotate(_s=Sum(amount))
                 .values('_s')             # 取出标量
        ),
        Value(0, output_field=DecimalField(max_digits=max_digits, decimal_places=decimal_places)),
    )


def restql_wants(request, field_names):
    """django-restql 稀疏字段判断: 用于"不需要的字段就不做昂贵注解"。

    未带 query 参数 -> 视为需要全部字段(保持默认行为);
    带了 query -> 仅当其中点名了任一 field_names 时才认为需要。
    """
    query = request.query_params.get('query') if request else None
    if not query:
        return True
    return any(name in query for name in field_names)
