"""DMS realtime signals — broadcast model lifecycle events to the realtime layer.

Connect these handlers in ``DMSConfig.ready()`` so they are registered once
at startup.

Design principles
-----------------
* Best-effort: a failure to broadcast must never raise or block the calling
  request.  All exceptions are caught and logged via structlog.
* No async in the signal handlers: the realtime backend's ``publish()`` call
  is synchronous (the ChannelsRealtimeBackend wraps async_to_sync internally).
* Deleted objects (``is_deleted=True``) still broadcast a ``*.deleted`` event
  so UIs can remove the item from state.
"""

from __future__ import annotations

import structlog
from django.db.models.signals import post_delete, post_save
from django.dispatch import receiver

_log = structlog.get_logger("dms.signals")


# ---------------------------------------------------------------------------
# Document signals
# ---------------------------------------------------------------------------

def _connect_document_signals() -> None:
    from simorgh.apps.dms.documents.models import Document

    @receiver(post_save, sender=Document, dispatch_uid="dms.signals.document_saved")
    def _document_saved(sender, instance: Document, created: bool, **kwargs: object) -> None:
        try:
            from simorgh.apps.dms.realtime import publish_document_event

            event = "document.created" if created else "document.updated"
            payload = {
                "id": str(instance.public_id),
                "title": instance.title,
                "status": instance.status,
            }
            publish_document_event(str(instance.public_id), event, payload)
        except Exception:
            _log.warning("dms.signals.document_saved.error", exc_info=True)

    @receiver(post_delete, sender=Document, dispatch_uid="dms.signals.document_deleted")
    def _document_deleted(sender, instance: Document, **kwargs: object) -> None:
        try:
            from simorgh.apps.dms.realtime import publish_document_event

            publish_document_event(
                str(instance.public_id),
                "document.deleted",
                {"id": str(instance.public_id)},
            )
        except Exception:
            _log.warning("dms.signals.document_deleted.error", exc_info=True)


# ---------------------------------------------------------------------------
# DocumentVersion signals
# ---------------------------------------------------------------------------

def _connect_version_signals() -> None:
    from simorgh.apps.dms.documents.models import DocumentVersion

    @receiver(post_save, sender=DocumentVersion, dispatch_uid="dms.signals.version_saved")
    def _version_saved(
        sender, instance: DocumentVersion, created: bool, **kwargs: object
    ) -> None:
        if not created:
            return
        try:
            from simorgh.apps.dms.realtime import publish_document_event

            doc = instance.document
            payload = {
                "version": f"{instance.version_major}.{instance.version_minor}",
                "status": instance.status,
                "document_id": str(doc.public_id),
            }
            publish_document_event(str(doc.public_id), "version.added", payload)
        except Exception:
            _log.warning("dms.signals.version_saved.error", exc_info=True)


# ---------------------------------------------------------------------------
# Comment signals
# ---------------------------------------------------------------------------

def _connect_comment_signals() -> None:
    from simorgh.apps.dms.collaboration.models import Comment

    @receiver(post_save, sender=Comment, dispatch_uid="dms.signals.comment_saved")
    def _comment_saved(
        sender, instance: Comment, created: bool, **kwargs: object
    ) -> None:
        try:
            from simorgh.apps.dms.realtime import publish_comment_event

            doc = instance.document
            event = "comment.created" if created else "comment.updated"
            payload = {
                "id": str(instance.public_id),
                "document_id": str(doc.public_id),
                "is_resolved": instance.is_resolved,
            }
            publish_comment_event(str(doc.public_id), event, payload)
        except Exception:
            _log.warning("dms.signals.comment_saved.error", exc_info=True)


def connect_all() -> None:
    """Register all DMS realtime signal handlers.

    Called once from ``DMSConfig.ready()``.
    """
    _connect_document_signals()
    _connect_version_signals()
    _connect_comment_signals()
