"""
NotificationAdmin – reusable Django admin for the Notification model.

No project-specific dependencies. Works with any custom User model.
"""
from __future__ import annotations

import json
from datetime import timedelta

from django.contrib import admin, messages
from django.db.models import Count, Q
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.utils import timezone
from django.utils.html import format_html
from django.utils.translation import gettext_lazy as _

from django_notify_hub.models import Notification, NotificationTemplate
from django_notify_hub.repositories import NotificationRepository
from django_notify_hub.types import NotificationChannel, NotificationPriority


def _pretty_json(value) -> str:
    if not value:
        return "-"
    try:
        return format_html(
            '<pre style="max-width:400px;white-space:pre-wrap">{}</pre>',
            json.dumps(value, indent=2, ensure_ascii=False),
        )
    except Exception:
        return str(value)


class ReadStatusFilter(admin.SimpleListFilter):
    title = _("Read Status")
    parameter_name = "read_status"

    def lookups(self, request, model_admin):
        return [
            ("unread", _("Unread")),
            ("read", _("Read")),
            ("read_today", _("Read Today")),
        ]

    def queryset(self, request, queryset):
        today = timezone.now().date()
        if self.value() == "unread":
            return queryset.filter(is_read=False)
        if self.value() == "read":
            return queryset.filter(is_read=True)
        if self.value() == "read_today":
            return queryset.filter(is_read=True, updated_at__date=today)
        return queryset


class ChannelFilter(admin.SimpleListFilter):
    title = _("Channel")
    parameter_name = "resolved_channel"

    def lookups(self, request, model_admin):
        return [(channel.value, channel.value) for channel in NotificationChannel]

    def queryset(self, request, queryset):
        if not self.value():
            return queryset
        return queryset.filter(
            Q(custom_channel=self.value()) | Q(template__channel=self.value())
        )


class PriorityFilter(admin.SimpleListFilter):
    title = _("Priority")
    parameter_name = "resolved_priority"

    def lookups(self, request, model_admin):
        return [(priority.value, priority.name.title()) for priority in NotificationPriority]

    def queryset(self, request, queryset):
        if not self.value():
            return queryset
        return queryset.filter(
            Q(custom_priority=self.value()) | Q(template__priority=self.value())
        )


@admin.register(NotificationTemplate)
class NotificationTemplateAdmin(admin.ModelAdmin):
    list_display = (
        "id",
        "title_preview",
        "channel",
        "priority",
        "notification_count",
        "created_at",
    )
    list_filter = ("channel", "priority", ("created_at", admin.DateFieldListFilter))
    search_fields = ("channel", "priority")
    readonly_fields = ("created_at", "pretty_title", "pretty_body", "pretty_data")

    @admin.display(description=_("Title"))
    def title_preview(self, obj: NotificationTemplate) -> str:
        return obj.get_title()[:60]

    @admin.display(ordering="notification_count_value", description=_("Recipients"))
    def notification_count(self, obj: NotificationTemplate) -> int:
        return getattr(obj, "notification_count_value", obj.notifications.count())

    @admin.display(description=_("Title translations"))
    def pretty_title(self, obj: NotificationTemplate) -> str:
        return _pretty_json(obj.title)

    @admin.display(description=_("Body translations"))
    def pretty_body(self, obj: NotificationTemplate) -> str:
        return _pretty_json(obj.body)

    @admin.display(description=_("Data"))
    def pretty_data(self, obj: NotificationTemplate) -> str:
        return _pretty_json(obj.data)

    def get_queryset(self, request):
        return super().get_queryset(request).annotate(
            notification_count_value=Count("notifications")
        )


@admin.register(Notification)
class NotificationAdmin(admin.ModelAdmin):
    list_display = (
        "id",
        "title_preview",
        "recipient_display",
        "channel_display",
        "priority_display",
        "status_badge",
        "created_at",
    )
    list_select_related = ("to_user", "template")
    list_filter = (ReadStatusFilter, ("created_at", admin.DateFieldListFilter), ChannelFilter, PriorityFilter)
    search_fields = ("to_user__email", "to_user__username")
    readonly_fields = ("created_at", "updated_at", "pretty_data")
    actions = ["mark_as_read", "mark_as_unread", "delete_old_read_selected"]

    # ── Display helpers ───────────────────────────────────────────────────

    @admin.display(description=_("Title"))
    def title_preview(self, obj: Notification) -> str:
        return obj.get_title()[:60]

    @admin.display(description=_("Recipient"))
    def recipient_display(self, obj: Notification) -> str:
        user = obj.to_user
        return str(getattr(user, "email", None) or getattr(user, "username", None) or user.pk)

    @admin.display(description=_("Channel"))
    def channel_display(self, obj: Notification) -> str:
        return obj.channel

    @admin.display(description=_("Priority"))
    def priority_display(self, obj: Notification) -> str:
        return obj.priority

    @admin.display(description=_("Status"))
    def status_badge(self, obj: Notification):
        colour = "#28a745" if obj.is_read else "#dc3545"
        label = _("Read") if obj.is_read else _("Unread")
        return format_html(
            '<span style="background:{};color:#fff;padding:2px 8px;border-radius:8px">{}</span>',
            colour, label,
        )

    @admin.display(description=_("Data"))
    def pretty_data(self, obj: Notification) -> str:
        return _pretty_json(obj.data)

    # ── Admin actions ─────────────────────────────────────────────────────

    @admin.action(description=_("Mark selected as read"))
    def mark_as_read(self, request, queryset):
        updated = queryset.update(is_read=True, status="read")
        self.message_user(request, _("%(n)d notifications marked as read.") % {"n": updated})

    @admin.action(description=_("Mark selected as unread"))
    def mark_as_unread(self, request, queryset):
        updated = queryset.update(is_read=False, status="pending")
        self.message_user(request, _("%(n)d notifications marked as unread.") % {"n": updated})

    @admin.action(description=_("Delete old read notifications (30+ days)"))
    def delete_old_read_selected(self, request, queryset):
        threshold = timezone.now() - timedelta(days=30)
        deleted, _ = queryset.filter(is_read=True, created_at__lt=threshold).delete()
        self.message_user(request, _("%(n)d old read notifications deleted.") % {"n": deleted})

    # ── Changelist with stats ─────────────────────────────────────────────

    def changelist_view(self, request, extra_context=None):
        extra_context = extra_context or {}
        extra_context["notification_stats"] = NotificationRepository.get_stats()

        if request.method == "POST" and "delete_all_old_read" in request.POST:
            deleted = NotificationRepository.delete_old_read(days=30)
            self.message_user(
                request,
                _("%(n)d old read notifications deleted.") % {"n": deleted},
                messages.SUCCESS,
            )
            url = reverse(
                f"admin:{self.model._meta.app_label}_{self.model._meta.model_name}_changelist"
            )
            return HttpResponseRedirect(url)

        return super().changelist_view(request, extra_context=extra_context)

    def get_queryset(self, request):
        return super().get_queryset(request).select_related("to_user", "template")

