"""QuerySet helpers for repository Documents — visibility-aware filtering."""

from __future__ import annotations

from django.db import models
from django.db.models import Q
from django.utils import timezone
from guardian.shortcuts import get_objects_for_user


class DocumentQuerySet(models.QuerySet):
    def published(self):
        # FRREP-VL006 — a retention "archive" action hides the document from
        # active listings without touching its FSM status.
        return self.filter(status="published").exclude(is_archived=True)

    def public(self):
        from apps.repository.documents.models import Collection, Document
        # Effective visibility = document.visibility OR collection.visibility (when INHERIT)
        return self.published().filter(
            Q(visibility=Document.Visibility.PUBLIC_OPEN)
            | Q(visibility=Document.Visibility.INHERIT, collection__visibility=Collection.Visibility.PUBLIC_OPEN)
        )

    def in_collection(self, collection):
        return self.filter(collection=collection)

    def by_grant(self, grant_reference: str):
        return self.filter(grant_reference=grant_reference)

    def for_user(self, user):
        """Visibility-aware queryset.

        Anonymous → only public open access.
        Authenticated non-staff → public + authenticated + per-document guardian grants
            + collections explicitly granted to one of the user's auth.Groups via
            ``CollectionGroupAccess`` (FRREP-AC005).
        Superuser / repo_manager / admin → all published + their own drafts.
        """
        from apps.core.permissions.roles import UserRole
        from apps.repository.documents.models import Collection, Document

        if not user or not user.is_authenticated:
            return self.public()

        if user.is_superuser or getattr(user, "role", "") in {
            UserRole.ADMIN,
            UserRole.SYSTEM_ADMIN,
            UserRole.REPO_MANAGER,
        }:
            return self.all()

        published = self.published().filter(
            Q(visibility__in=[Document.Visibility.PUBLIC_OPEN, Document.Visibility.AUTHENTICATED])
            | Q(
                visibility=Document.Visibility.INHERIT,
                collection__visibility__in=[
                    Collection.Visibility.PUBLIC_OPEN,
                    Collection.Visibility.AUTHENTICATED,
                ],
            )
        )

        # Per-document explicit grants via guardian (download_document or view).
        granted = get_objects_for_user(
            user,
            ["repository_documents.view_document", "repository_documents.download_document"],
            klass=self.model,
            any_perm=True,
        )

        # Collection-level group grants (FRREP-AC005). A user inherits view rights
        # to every published document in any collection where one of their groups
        # holds an active CollectionGroupAccess grant.
        now = timezone.now()
        group_granted_collection_ids = (
            Collection.objects
            .filter(group_access__group__in=user.groups.all())
            .filter(
                Q(group_access__expires_at__isnull=True)
                | Q(group_access__expires_at__gt=now)
            )
            .values_list("id", flat=True)
            .distinct()
        )
        group_granted = self.published().filter(collection_id__in=group_granted_collection_ids)

        own = self.filter(submitted_by=user)
        return (published | granted | group_granted | own).distinct()


class DocumentManager(models.Manager.from_queryset(DocumentQuerySet)):
    pass
