"""Operational-scope policy for procurement records.

Capability permissions answer what a user may do. This module answers which
procurement records that capability may operate on.
"""
from django.db.models import Q

from apps.core.permissions import user_has_full_scope, user_is_finance_authority, user_is_procurement_authority, user_managed_department_ids


def requisition_scope_q(user, organization):
    if user_has_full_scope(user, "procurements", organization):
        return Q()
    managed = user_managed_department_ids(user)
    scope = Q(requested_by=user)
    if managed:
        scope |= Q(requesting_department_id__in=managed)
    scope |= Q(project__team_members__user=user)
    return scope


def visible_requisitions(queryset, user, organization):
    queryset = queryset.filter(organization=organization)
    if user_has_full_scope(user, "procurements", organization) or user_is_procurement_authority(user, organization) or user_is_finance_authority(user, organization):
        return queryset
    return queryset.filter(requisition_scope_q(user, organization)).distinct()


def visible_purchase_orders(queryset, user, organization):
    queryset = queryset.filter(organization=organization)
    if user_has_full_scope(user, "procurements", organization) or user_is_procurement_authority(user, organization) or user_is_finance_authority(user, organization):
        return queryset
    managed = user_managed_department_ids(user)
    scope = Q(requisition__requested_by=user) | Q(created_by=user)
    if managed:
        scope |= Q(requisition__requesting_department_id__in=managed)
    scope |= Q(requisition__project__team_members__user=user)
    return queryset.filter(scope).distinct()


def visible_via_requisition(queryset, user, path, organization, finance_only=False, has_own_organization=True):
    org_lookup = "organization" if has_own_organization else f"{path}__organization"
    queryset = queryset.filter(**{org_lookup: organization})
    authority = user_is_finance_authority(user, organization) if finance_only else (user_is_procurement_authority(user, organization) or user_is_finance_authority(user, organization))
    if user_has_full_scope(user, "procurements", organization) or authority:
        return queryset
    managed = user_managed_department_ids(user)
    scope = Q(**{f"{path}__requested_by": user})
    if managed:
        scope |= Q(**{f"{path}__requesting_department_id__in": managed})
    scope |= Q(**{f"{path}__project__team_members__user": user})
    return queryset.filter(scope).distinct()


def user_can_request_for(user, organization, department=None, project=None):
    if user_has_full_scope(user, "procurements", organization):
        return True
    if project and project.team_members.filter(user=user).exists():
        return True
    if department and user.department_memberships.filter(
        department=department, is_active=True,
    ).exists():
        return True
    return department is None and project is None
