from django.contrib import admin, messages
from django.utils import timezone
from unfold.admin import ModelAdmin, TabularInline
from unfold.contrib.filters.admin import RangeDateTimeFilter
from unfold.decorators import display

from core.admin_ui import PortalAdminMixin
from core.status_palette import NOTIFICATION_STATUS_LABELS
from .models import EmailSuppression, NotificationAttempt, NotificationLog, NotificationTemplate
from .workflows import retry_failed_notifications, send_notification


class NotificationAttemptInline(TabularInline):
    model = NotificationAttempt
    extra = 0
    can_delete = False
    fields = ("attempted_at", "result", "recipient_used", "backend", "duration_ms", "error_message", "triggered_by")
    readonly_fields = fields
    tab = True

    def has_add_permission(self, request, obj=None):
        return False


@admin.action(description="Enviar notificações selecionadas")
def send_selected_notifications(modeladmin, request, queryset):
    sent = failed = suppressed = 0
    for notification in queryset.exclude(status__in=[NotificationLog.Status.SENT, NotificationLog.Status.CANCELLED]):
        delivered = send_notification(notification, user=request.user, raise_errors=False)
        if delivered.status == NotificationLog.Status.SENT:
            sent += 1
        elif delivered.status == NotificationLog.Status.SUPPRESSED:
            suppressed += 1
        else:
            failed += 1
    if sent:
        modeladmin.message_user(request, f"{sent} notificações enviadas.", messages.SUCCESS)
    if suppressed:
        modeladmin.message_user(request, f"{suppressed} notificações bloqueadas pela lista de supressão.", messages.WARNING)
    if failed:
        modeladmin.message_user(request, f"{failed} notificações falharam. Consulte as tentativas de envio.", messages.ERROR)


@admin.action(description="Agendar para envio imediato")
def schedule_selected_now(modeladmin, request, queryset):
    count = queryset.exclude(status__in=[NotificationLog.Status.SENT, NotificationLog.Status.CANCELLED]).update(
        status=NotificationLog.Status.SCHEDULED,
        scheduled_for=timezone.now(),
        next_retry_at=None,
        error_message="",
    )
    modeladmin.message_user(request, f"{count} notificações agendadas.", messages.SUCCESS)


@admin.action(description="Repetir notificações falhadas")
def retry_selected_notifications(modeladmin, request, queryset):
    sent = failed = skipped = 0
    for notification in queryset.filter(status=NotificationLog.Status.FAILED):
        if not notification.can_retry:
            skipped += 1
            continue
        delivered = send_notification(notification, user=request.user, raise_errors=False)
        if delivered.status == NotificationLog.Status.SENT:
            sent += 1
        else:
            failed += 1
    modeladmin.message_user(
        request,
        f"Repetição concluída: {sent} enviadas, {failed} falharam, {skipped} sem novas tentativas disponíveis.",
        messages.SUCCESS if not failed else messages.WARNING,
    )


@admin.action(description="Cancelar notificações selecionadas")
def cancel_selected(modeladmin, request, queryset):
    count = queryset.exclude(status=NotificationLog.Status.SENT).update(
        status=NotificationLog.Status.CANCELLED,
        scheduled_for=None,
        next_retry_at=None,
    )
    modeladmin.message_user(request, f"{count} notificações canceladas.", messages.SUCCESS)


@admin.action(description="Repor como rascunho")
def mark_as_draft(modeladmin, request, queryset):
    count = queryset.exclude(status=NotificationLog.Status.SENT).update(
        status=NotificationLog.Status.DRAFT,
        scheduled_for=None,
        next_retry_at=None,
        error_message="",
    )
    modeladmin.message_user(request, f"{count} notificações repostas como rascunho.", messages.SUCCESS)


@admin.register(NotificationTemplate)
class NotificationTemplateAdmin(PortalAdminMixin, ModelAdmin):
    portal_icon = "drafts"
    portal_kicker = "COMUNICAÇÕES"
    portal_description = "Modelos em texto e HTML para avisos de renovação, confirmações e mensagens aos clientes."
    portal_tone = "violet"
    portal_stats = (
        {"label": "Modelos", "icon": "drafts", "tone": "primary", "caption": "Total disponível"},
        {"label": "Ativos", "icon": "check_circle", "tone": "success", "filters": {"is_active": True}, "caption": "Prontos a usar"},
        {"label": "Automáticos", "icon": "automation", "tone": "cyan", "filters": {"allow_automatic_send": True}, "caption": "Autorizados para envio"},
        {"label": "Inativos", "icon": "pause_circle", "tone": "warning", "filters": {"is_active": False}, "caption": "Fora de utilização"},
    )
    portal_related_links = (
        {"label": "Centro de comunicações", "icon": "campaign", "url_name": "communications_center"},
        {"label": "Notificações", "icon": "notifications", "url_name": "admin:notifications_notificationlog_changelist"},
        {"label": "Renovações", "icon": "event_repeat", "url_name": "admin:billing_renewal_changelist"},
    )

    list_display = ("code", "notification_type", "is_active", "allow_automatic_send", "send_to_billing_contacts", "updated_at")
    list_filter = ("notification_type", "is_active", "allow_automatic_send", "send_to_billing_contacts")
    search_fields = ("code", "subject_template", "body_template", "html_body_template")
    list_editable = ("is_active", "allow_automatic_send")
    list_fullwidth = True
    fieldsets = (
        ("Modelo", {"fields": ("code", "notification_type", "is_active"), "description": "Identificação interna e contexto em que o modelo será usado."}),
        ("Automação e destinatários", {"fields": ("allow_automatic_send", "send_to_billing_contacts"), "description": "Regras de envio automático e inclusão de contactos financeiros."}),
        ("Conteúdo", {"fields": ("subject_template", "body_template", "html_body_template"), "description": "Pode usar as variáveis documentadas no campo da mensagem."}),
        ("Sistema", {"fields": ("created_at", "updated_at"), "classes": ("collapse",)}),
    )
    readonly_fields = ("created_at", "updated_at")


@admin.register(NotificationLog)
class NotificationLogAdmin(PortalAdminMixin, ModelAdmin):
    portal_icon = "notifications"
    portal_kicker = "COMUNICAÇÕES"
    portal_description = "Fila, agendamento, histórico, modo de testes e tentativas de entrega de todas as mensagens."
    portal_tone = "cyan"
    portal_stats = (
        {"label": "Comunicações", "icon": "notifications", "tone": "primary", "caption": "Histórico total"},
        {"label": "Agendadas", "icon": "schedule_send", "tone": "cyan", "filters": {"status": NotificationLog.Status.SCHEDULED}, "caption": "Na fila de envio"},
        {"label": "Enviadas", "icon": "mark_email_read", "tone": "success", "filters": {"status": NotificationLog.Status.SENT}, "caption": "Com sucesso"},
        {"label": "Falharam", "icon": "error", "tone": "danger", "filters": {"status": NotificationLog.Status.FAILED}, "caption": "Requer intervenção"},
    )
    portal_related_links = (
        {"label": "Centro de comunicações", "icon": "campaign", "url_name": "communications_center"},
        {"label": "Modelos", "icon": "drafts", "url_name": "admin:notifications_notificationtemplate_changelist"},
        {"label": "Emails bloqueados", "icon": "unsubscribe", "url_name": "admin:notifications_emailsuppression_changelist"},
        {"label": "Renovações", "icon": "event_repeat", "url_name": "admin:billing_renewal_changelist"},
    )

    list_display = (
        "notification_identity", "client", "delivery_mode", "show_status", "attempts_progress", "scheduled_for", "sent_at"
    )
    list_filter = (
        "channel", "status", "delivery_mode", "is_automatic", ("scheduled_for", RangeDateTimeFilter), ("sent_at", RangeDateTimeFilter)
    )
    search_fields = (
        "client__name", "recipient", "original_recipient", "subject", "body", "error_message", "service__name", "message_id"
    )
    autocomplete_fields = ("client", "service", "renewal", "template", "sent_by")
    readonly_fields = (
        "public_id", "original_recipient", "delivery_mode", "attempts_count", "last_attempt_at", "next_retry_at", "message_id", "sent_at", "created_at", "updated_at"
    )
    inlines = (NotificationAttemptInline,)
    actions = (send_selected_notifications, schedule_selected_now, retry_selected_notifications, cancel_selected, mark_as_draft)
    list_filter_submit = True
    list_fullwidth = True

    fieldsets = (
        ("Destinatário", {"fields": ("client", "service", "renewal", "template", "channel", "recipient", "original_recipient", "cc_recipients", "reply_to"), "description": "Contexto, destinatário e cópias da comunicação."}),
        ("Mensagem", {"fields": ("subject", "body", "html_body"), "description": "Conteúdo em texto e HTML."}),
        ("Fila e automação", {"fields": ("status", "is_automatic", "scheduled_for", "delivery_mode"), "description": "Estado operacional, agendamento e modo de entrega."}),
        ("Entrega", {"fields": ("sent_at", "sent_by", "attempts_count", "max_attempts", "last_attempt_at", "next_retry_at", "message_id", "error_message"), "description": "Resultado e controlo de repetições."}),
        ("Sistema", {"fields": ("public_id", "deduplication_key", "created_at", "updated_at"), "classes": ("collapse",)}),
    )

    @display(description="Notificação", header=True)
    def notification_identity(self, obj):
        return obj.subject or obj.get_channel_display(), obj.original_recipient or obj.recipient

    @display(description="Estado", label=NOTIFICATION_STATUS_LABELS, ordering="status")
    def show_status(self, obj):
        return obj.get_status_display()

    @display(description="Tentativas")
    def attempts_progress(self, obj):
        return f"{obj.attempts_count}/{obj.max_attempts}"

    def save_model(self, request, obj, form, change):
        if obj.status == NotificationLog.Status.SCHEDULED and not obj.scheduled_for:
            obj.scheduled_for = timezone.now()
        super().save_model(request, obj, form, change)


@admin.register(NotificationAttempt)
class NotificationAttemptAdmin(PortalAdminMixin, ModelAdmin):
    portal_icon = "outbox"
    portal_kicker = "COMUNICAÇÕES"
    portal_description = "Auditoria técnica imutável de cada tentativa de envio, destinatário usado e erro devolvido."
    portal_tone = "navy"
    portal_stats = (
        {"label": "Tentativas", "icon": "outbox", "tone": "primary", "caption": "Total registado"},
        {"label": "Sucesso", "icon": "check_circle", "tone": "success", "filters": {"result": NotificationAttempt.Result.SUCCESS}, "caption": "Entregues ao backend"},
        {"label": "Falhas", "icon": "error", "tone": "danger", "filters": {"result": NotificationAttempt.Result.FAILED}, "caption": "Erros técnicos"},
        {"label": "Bloqueadas", "icon": "unsubscribe", "tone": "warning", "filters": {"result": NotificationAttempt.Result.SUPPRESSED}, "caption": "Lista de supressão"},
    )
    list_display = ("attempted_at", "notification", "result", "recipient_used", "backend", "duration_ms", "triggered_by")
    list_filter = ("result", "backend", ("attempted_at", RangeDateTimeFilter))
    search_fields = ("notification__subject", "recipient_used", "error_message", "message_id")
    readonly_fields = ("notification", "attempted_at", "result", "recipient_used", "backend", "duration_ms", "message_id", "error_message", "triggered_by")
    list_fullwidth = True

    def has_add_permission(self, request):
        return False

    def has_change_permission(self, request, obj=None):
        return False

    def has_delete_permission(self, request, obj=None):
        return False


@admin.register(EmailSuppression)
class EmailSuppressionAdmin(PortalAdminMixin, ModelAdmin):
    portal_icon = "unsubscribe"
    portal_kicker = "COMUNICAÇÕES"
    portal_description = "Lista de segurança para impedir envios a endereços inválidos, devolvidos ou bloqueados."
    portal_tone = "amber"
    portal_stats = (
        {"label": "Endereços", "icon": "unsubscribe", "tone": "primary", "caption": "Total registado"},
        {"label": "Bloqueios ativos", "icon": "block", "tone": "danger", "filters": {"is_active": True}, "caption": "Não recebem email"},
        {"label": "Desativados", "icon": "check_circle", "tone": "success", "filters": {"is_active": False}, "caption": "Envio permitido"},
    )
    list_display = ("email", "reason", "is_active", "updated_at")
    list_filter = ("reason", "is_active")
    search_fields = ("email", "description")
    list_editable = ("is_active",)
    readonly_fields = ("public_id", "created_at", "updated_at")
    fieldsets = (
        ("Bloqueio", {"fields": ("email", "reason", "is_active")}),
        ("Contexto", {"fields": ("description",)}),
        ("Sistema", {"fields": ("public_id", "created_at", "updated_at"), "classes": ("collapse",)}),
    )
