"""
`/api/captures/` — the ninth and last slice, and the one that breaks every
shape the other eight share.

**IT DOES NOT INHERIT `PageScopedViewSet`.** There is no `?page=`, no bulk
endpoint and no `sample` endpoint, because there is one global inbox: capture
first, choose a Space later. The queryset filters by `user` directly, which is
the one place in `lifey_api` that ownership is a single hop rather than a walk
through a page to a space.

**`pagination_class = None`, AND IT IS NOT A PREFERENCE.**
`features/quick-capture/data/api.js`'s `listCaptures` is the ONE list reader in
the client that does not do `body.results ?? body` — it maps `rows` directly.
Switch the default paginator on here and the inbox comes back empty, on a
screen whose whole job is to show you what you wrote down. The honest fix is
that one line of the client; until it ships, this line is what keeps the
feature working. A capture is two short strings, and an inbox is bounded by how
much somebody types.

The extra endpoint is `GET /api/captures/sample-state/`, returning
`{all_sample}` — see below.
"""

from drf_spectacular.utils import extend_schema, inline_serializer
from rest_framework import serializers, viewsets
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

from ..models import Capture
from ..permissions import IsOwner
from ..serializers.capture import CaptureSerializer


class CaptureViewSet(viewsets.ModelViewSet):
    serializer_class = CaptureSerializer
    permission_classes = [IsAuthenticated, IsOwner]

    # Never used at runtime — `get_queryset` replaces it. Here so
    # `manage.py spectacular` can derive the model without a request, since the
    # committed schema is the only check against contract drift.
    queryset = Capture.objects.none()

    # See the module docstring. Removing this line empties the inbox.
    pagination_class = None

    def get_queryset(self):
        return Capture.objects.filter(user=self.request.user).select_related('triaged_to')

    def perform_create(self, serializer):
        # The owner comes from the token, never from the body.
        serializer.save(user=self.request.user)

    @extend_schema(
        summary='Whether every capture in the inbox is still example data.',
        responses=inline_serializer(
            name='CaptureSampleState',
            fields={'all_sample': serializers.BooleanField()},
        ),
    )
    @action(detail=False, methods=['get'], url_path='sample-state')
    def sample_state(self, request):
        """
        `{all_sample}` — true when the inbox is non-empty and every row in it
        is still seeded example data.

        It exists because "Clear the example data" has to know whether there is
        anything of the user's mixed in. **An empty inbox is FALSE, not true**,
        matching the client's `isAllSample` (`all.length > 0 && …`): offering
        to clear example data on an inbox with nothing in it is an action that
        would do nothing and read as broken.

        Two `EXISTS` rather than one `COUNT` and a scan: the question is "is
        there any" both times, and fetching the rows to answer a boolean is the
        kind of cost that only appears once somebody has a real inbox.
        """
        mine = Capture.objects.filter(user=request.user)
        has_any = mine.exists()
        has_own = mine.filter(is_sample=False).exists()
        return Response({'all_sample': has_any and not has_own})
