"""Cross-app signal receivers for SME-Hub showcasing (SP4).

  • Refreshes the AI matchmaking snapshot when an entrepreneur's match inputs
    change (catalogue published / participant confirmed / agreement formalised).
  • Bumps DealRoom.last_activity_at on every message + document event so the
    deal-room expiry beat (FRSME-ISD016) can prefer activity-based extension
    in future iterations.
  • Cascades SP1 business revocation (FRSME-OBR029): withdraws active
    showcase applications and closes any open Deal Room linked to the
    revoked business.
"""
from __future__ import annotations

import logging

from django.dispatch import receiver
from django.utils import timezone

from apps.smehub.onboarding import signals as onb_signals
from apps.smehub.showcasing import signals as showcase_signals

logger = logging.getLogger(__name__)


def _refresh_for_user(user, *, trigger: str) -> None:
    if user is None:
        return
    try:
        from apps.smehub.linkage.ai_matchmaking import refresh_recommendations
        from apps.smehub.onboarding.models import EntrepreneurProfile
    except Exception:
        return
    profile = EntrepreneurProfile.objects.filter(user=user).first()
    if profile is None:
        return
    refresh_recommendations(profile, trigger=trigger)


@receiver(showcase_signals.smehub_showcase_participant_confirmed)
def _on_participant_confirmed(sender, application, by_user=None, **kwargs):
    user = getattr(application.entrepreneur, "user", None)
    _refresh_for_user(user, trigger="showcase_participant_confirmed")


@receiver(showcase_signals.smehub_catalogue_published)
def _on_catalogue_published(sender, entry, by_user=None, **kwargs):
    user = getattr(entry.entrepreneur, "user", None)
    _refresh_for_user(user, trigger="catalogue_published")


@receiver(showcase_signals.smehub_agreement_formalised)
def _on_agreement_formalised(sender, deal_room, agreement, by_user=None, **kwargs):
    user = getattr(deal_room.entrepreneur, "user", None)
    _refresh_for_user(user, trigger="agreement_formalised")


@receiver(showcase_signals.smehub_deal_room_message_posted)
def _bump_activity_on_message(sender, message, **kwargs):
    DealRoom = type(message.deal_room)
    DealRoom.objects.filter(pk=message.deal_room_id).update(last_activity_at=timezone.now())


@receiver(showcase_signals.smehub_deal_room_document_uploaded)
def _bump_activity_on_document(sender, document, **kwargs):
    DealRoom = type(document.deal_room)
    DealRoom.objects.filter(pk=document.deal_room_id).update(last_activity_at=timezone.now())


# ---------------------------------------------------------------------------
# OBR029 revoke cascade
# ---------------------------------------------------------------------------

@receiver(onb_signals.smehub_business_revoked, dispatch_uid="smehub.showcasing.revoke_cascade")
def _on_business_revoked(sender, business=None, by_user=None, reason: str = "", **kwargs):
    """Withdraw active showcase applications and close any open Deal Rooms
    linked to a revoked business (FRSME-OBR029)."""
    if business is None:
        return

    from apps.core.notifications.models import Notification
    from apps.smehub._shared.notifications import notify_smehub
    from apps.smehub.showcasing.models import DealRoom, ShowcaseApplication

    Verb = Notification.Verb

    apps_qs = ShowcaseApplication.objects.filter(
        business=business,
        status__in=[
            ShowcaseApplication.Status.SUBMITTED,
            ShowcaseApplication.Status.UNDER_REVIEW,
            ShowcaseApplication.Status.CONFIRMED,
        ],
    ).select_related("entrepreneur__user")
    for app in apps_qs:
        try:
            app.withdraw()
            app.save(update_fields=["status"])
        except Exception:
            logger.exception("SP4 cascade withdraw failed for showcase application %s", app.pk)
            continue
        try:
            notify_smehub(
                app.entrepreneur.user,
                message=(
                    f"Your showcase application \"{app.innovation_title}\" was "
                    f"withdrawn because the underlying business profile was revoked."
                ),
                verb=Verb.SMEHUB_SHOWCASE_PARTICIPANT_CONFIRMED,
                target=app,
            )
        except Exception:
            logger.exception("Cascade notification failed for showcase application %s", app.pk)

    rooms = DealRoom.objects.filter(
        business=business, status=DealRoom.Status.OPEN,
    ).select_related("entrepreneur__user")
    for room in rooms:
        try:
            room.close(reason=f"Business revoked. {reason}".strip())
            room.save(update_fields=["status", "closed_at", "closed_reason"])
        except Exception:
            logger.exception("SP4 cascade close failed for deal room %s", room.pk)
            continue
        try:
            notify_smehub(
                room.entrepreneur.user,
                message=(
                    f"Deal Room {room.room_id} was closed because the "
                    f"underlying business profile was revoked."
                ),
                verb=Verb.SMEHUB_DEAL_ROOM_EXPIRED,
                target=room,
            )
        except Exception:
            logger.exception("Cascade notification failed for deal room %s", room.pk)
