"""DMS notification handlers.

Event-bus subscribers and Django signal handlers that convert DMS domain
events into platform Notification rows via ``dispatch_dms_notification``.

All handlers are best-effort: exceptions are caught and logged so that a
failing notification path never breaks the core DMS workflow.

Subscriptions are registered when this module is imported (in
``DMSConfig.ready()``).  Django signal connections are made in apps.py
using ``dispatch_uid`` to ensure idempotency.
"""

from __future__ import annotations

import logging
import uuid

from simorgh.apps.events.bus import subscribe

from simorgh.apps.dms.notifications.services import dispatch_dms_notification

_log = logging.getLogger("simorgh.dms.notifications")


# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

def _lookup_document(document_id: str, tenant_id: int):
    """Return Document or None, tolerating bad UUIDs."""
    try:
        from simorgh.apps.dms.documents.models import Document

        return Document.objects.filter(
            public_id=uuid.UUID(str(document_id)),
            tenant_id=tenant_id,
        ).first()
    except Exception:
        return None


# ---------------------------------------------------------------------------
# Event-bus subscribers
# ---------------------------------------------------------------------------

@subscribe("dms.document.published")
def on_document_published(payload: dict) -> None:
    """Notify the document creator when a document is published."""
    try:
        document_id = payload.get("document_id")
        tenant_id = payload.get("tenant_id")
        if not document_id or not tenant_id:
            return
        doc = _lookup_document(document_id, tenant_id)
        if doc is None or doc.created_by_id is None:
            return
        dispatch_dms_notification(
            "dms.document_published",
            recipients=[doc.created_by_id],
            context={"document_title": doc.title},
            tenant_id=doc.tenant_id,
            organization_node_id=doc.organization_node_id,
        )
    except Exception:
        _log.warning("dms.notifications.on_document_published.error", exc_info=True)


@subscribe("dms.document.archived")
def on_document_archived(payload: dict) -> None:
    """Notify the document creator when a document is archived."""
    try:
        document_id = payload.get("document_id")
        tenant_id = payload.get("tenant_id")
        if not document_id or not tenant_id:
            return
        doc = _lookup_document(document_id, tenant_id)
        if doc is None or doc.created_by_id is None:
            return
        dispatch_dms_notification(
            "dms.document_archived",
            recipients=[doc.created_by_id],
            context={"document_title": doc.title},
            tenant_id=doc.tenant_id,
            organization_node_id=doc.organization_node_id,
        )
    except Exception:
        _log.warning("dms.notifications.on_document_archived.error", exc_info=True)


@subscribe("dms.document.submitted_for_review")
def on_document_submitted_for_review(payload: dict) -> None:
    """Notify the document creator when a document is submitted for review."""
    try:
        document_id = payload.get("document_id")
        tenant_id = payload.get("tenant_id")
        if not document_id or not tenant_id:
            return
        doc = _lookup_document(document_id, tenant_id)
        if doc is None or doc.created_by_id is None:
            return
        dispatch_dms_notification(
            "dms.document_submitted_for_review",
            recipients=[doc.created_by_id],
            context={"document_title": doc.title},
            tenant_id=doc.tenant_id,
            organization_node_id=doc.organization_node_id,
        )
    except Exception:
        _log.warning(
            "dms.notifications.on_document_submitted_for_review.error", exc_info=True
        )


@subscribe("dms.checkout.expired")
def on_checkout_expired(payload: dict) -> None:
    """Notify the lock holder when their checkout expires."""
    try:
        lock_id = payload.get("lock_id")
        tenant_id = payload.get("tenant_id")
        if not lock_id or not tenant_id:
            return
        from simorgh.apps.dms.versioning.models import DocumentLock

        lock = DocumentLock.objects.filter(
            public_id=uuid.UUID(str(lock_id)),
            tenant_id=tenant_id,
        ).select_related("document").first()
        if lock is None or lock.locked_by_id is None:
            return
        doc = lock.document
        dispatch_dms_notification(
            "dms.checkout_expired",
            recipients=[lock.locked_by_id],
            context={"document_title": doc.title},
            tenant_id=lock.tenant_id,
            organization_node_id=lock.organization_node_id,
        )
    except Exception:
        _log.warning("dms.notifications.on_checkout_expired.error", exc_info=True)


@subscribe("dms.hold.placed")
def on_hold_placed(payload: dict) -> None:
    """Notify the document creator when a legal hold is placed."""
    try:
        document_id = payload.get("document_id")
        tenant_id = payload.get("tenant_id")
        if not document_id or not tenant_id:
            return
        doc = _lookup_document(document_id, tenant_id)
        if doc is None or doc.created_by_id is None:
            return
        dispatch_dms_notification(
            "dms.hold_placed",
            recipients=[doc.created_by_id],
            context={"document_title": doc.title},
            tenant_id=doc.tenant_id,
            organization_node_id=doc.organization_node_id,
        )
    except Exception:
        _log.warning("dms.notifications.on_hold_placed.error", exc_info=True)


# ---------------------------------------------------------------------------
# Django signal handlers (connected in apps.py)
# ---------------------------------------------------------------------------

def on_mention_created(sender, instance, created, **kwargs) -> None:  # noqa: ANN001
    """Notify the mentioned user when a new @mention is created."""
    if not created:
        return
    if instance.is_notified:
        return
    try:
        dispatch_dms_notification(
            "dms.mention",
            recipients=[instance.mentioned_user_id],
            context={
                "document_title": instance.comment.document.title
                if hasattr(instance.comment, "document")
                else "",
            },
            tenant_id=instance.tenant_id,
            organization_node_id=instance.organization_node_id,
        )
        instance.is_notified = True
        instance.save(update_fields=["is_notified"])
    except Exception:
        _log.warning("dms.notifications.on_mention_created.error", exc_info=True)


def on_comment_resolved(sender, instance, created, **kwargs) -> None:  # noqa: ANN001
    """Notify the comment author when a comment thread is resolved."""
    if created:
        return
    update_fields = kwargs.get("update_fields")
    if update_fields is not None and "is_resolved" not in update_fields:
        return
    if not instance.is_resolved:
        return
    if instance.author_id is None:
        return
    try:
        dispatch_dms_notification(
            "dms.comment_resolved",
            recipients=[instance.author_id],
            context={"document_title": instance.document.title},
            tenant_id=instance.tenant_id,
            organization_node_id=instance.organization_node_id,
        )
    except Exception:
        _log.warning("dms.notifications.on_comment_resolved.error", exc_info=True)
