"""
NotificationViewSet – clean REST API for user and admin notification management.

Improvements over original:
- No hardcoded URLs or domain names.
- Uses Repository for all DB access.
- Consistent, well-typed responses.
- Proper input validation via dedicated serializers.
- Pagination enabled by default.
"""
from __future__ import annotations

from django.utils.translation import gettext_lazy as _
from rest_framework import status, viewsets
from rest_framework.decorators import action
from rest_framework.filters import OrderingFilter
from rest_framework.pagination import PageNumberPagination
from rest_framework.permissions import IsAdminUser, IsAuthenticated
from rest_framework.response import Response

from django_notify_hub.api.serializers import DeleteManySerializer, MarkReadSerializer, NotificationSerializer
from django_notify_hub.conf import app_settings
from django_notify_hub.models import Notification
from django_notify_hub.repositories import NotificationRepository


class NotificationPagination(PageNumberPagination):
    page_size_query_param = "page_size"

    @property
    def page_size(self):
        return app_settings.PAGINATION_PAGE_SIZE

    @property
    def max_page_size(self):
        return app_settings.PAGINATION_MAX_PAGE_SIZE


class NotificationViewSet(viewsets.ReadOnlyModelViewSet):
    """
    ViewSet providing read + lifecycle actions for notifications.

    Endpoints:
        GET  /notifications/              → admin: all notifications
        GET  /notifications/my/           → authenticated: current user's list
        GET  /notifications/unread-count/ → authenticated: unread count
        PATCH /notifications/{pk}/mark-read/   → authenticated: mark one read
        POST /notifications/mark-many-read/    → authenticated: mark many read
        DELETE /notifications/{pk}/            → authenticated: delete one
        POST /notifications/delete-many/       → authenticated: bulk delete
    """

    serializer_class = NotificationSerializer
    pagination_class = NotificationPagination
    filter_backends = [OrderingFilter]
    ordering_fields = ["created_at", "is_read"]
    ordering = ["-created_at"]

    def get_permissions(self):
        user_actions = {"my", "unread_count", "mark_read", "mark_many_read", "destroy", "delete_many"}
        if self.action in user_actions:
            return [IsAuthenticated()]
        return [IsAdminUser()]

    def get_queryset(self):
        if self.action == "list":
            qs = Notification.objects.all().select_related("to_user", "template")
            user_id = self.request.query_params.get("to_user")
            if user_id:
                qs = qs.filter(to_user__pk=user_id)
            return qs
        return Notification.objects.all().select_related("to_user", "template")

    # ── User-facing actions ───────────────────────────────────────────────

    @action(methods=["get"], detail=False, url_path="my")
    def my(self, request) -> Response:
        """Return paginated list of the current user's notifications."""
        qs = NotificationRepository.get_for_user(request.user)
        is_read = request.query_params.get("is_read")
        if is_read is not None:
            qs = qs.filter(is_read=is_read.lower() == "true")

        page = self.paginate_queryset(qs)
        serializer = self.get_serializer(page if page is not None else qs, many=True)
        if page is not None:
            return self.get_paginated_response(serializer.data)
        return Response(serializer.data)

    @action(methods=["get"], detail=False, url_path="unread-count")
    def unread_count(self, request) -> Response:
        count = NotificationRepository.get_unread_count(request.user)
        return Response({"unread_count": count})

    @action(methods=["patch"], detail=True, url_path="mark-read")
    def mark_read(self, request, pk=None) -> Response:
        updated = NotificationRepository.mark_read(pk, request.user)
        if not updated:
            return Response({"detail": _("Notification not found.")}, status=status.HTTP_404_NOT_FOUND)
        return Response({"detail": _("Notification marked as read.")})

    @action(methods=["post"], detail=False, url_path="mark-many-read")
    def mark_many_read(self, request) -> Response:
        serializer = MarkReadSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        pks = serializer.validated_data["pks"]
        updated = NotificationRepository.mark_many_read(pks, request.user)
        if updated == 0:
            return Response({"detail": _("No matching notifications found.")}, status=status.HTTP_404_NOT_FOUND)
        return Response({"detail": _("%(n)d notifications marked as read.") % {"n": updated}})

    def destroy(self, request, pk=None) -> Response:
        deleted, _del = Notification.objects.filter(pk=pk, to_user=request.user).delete()
        if not deleted:
            return Response({"detail": _("Not found.")}, status=status.HTTP_404_NOT_FOUND)
        return Response(status=status.HTTP_204_NO_CONTENT)

    @action(methods=["post"], detail=False, url_path="delete-many")
    def delete_many(self, request) -> Response:
        serializer = DeleteManySerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        pks = serializer.validated_data["pks"]
        deleted, _del = Notification.objects.filter(pk__in=pks, to_user=request.user).delete()
        return Response({"detail": _("%(n)d notifications deleted.") % {"n": deleted}})

