"""
Signal handlers for moderation-related FSM state transitions.

This module provides signal handlers that execute when moderation
models (EditSubmission, PhotoSubmission, ModerationReport, etc.)
undergo state transitions.

Includes:
- Transition handlers for approval, rejection, escalation
- Real-time broadcasting signal for dashboard updates
- Claim/unclaim tracking for concurrency control
"""

import logging

from django.dispatch import Signal

logger = logging.getLogger(__name__)


# ============================================================================
# Custom Signals for Real-Time Broadcasting
# ============================================================================

# Signal emitted when a submission status changes - for real-time UI updates
# Arguments:
#   - sender: The model class (EditSubmission or PhotoSubmission)
#   - submission_id: The ID of the submission
#   - submission_type: "edit" or "photo"
#   - new_status: The new status value
#   - previous_status: The previous status value
#   - locked_by: Username of the moderator who claimed it (or None)
#   - payload: Full payload dictionary for broadcasting
submission_status_changed = Signal()


def handle_submission_claimed(instance, source, target, user, context=None, **kwargs):
    """
    Handle submission claim transitions.

    Called when an EditSubmission or PhotoSubmission is claimed by a moderator.
    Broadcasts the status change for real-time dashboard updates.

    Args:
        instance: The submission instance.
        source: The source state.
        target: The target state.
        user: The user who claimed.
        context: Optional TransitionContext.
    """
    if target != "CLAIMED":
        return

    logger.info(f"Submission {instance.pk} claimed by {user.username if user else 'system'}")

    # Broadcast for real-time dashboard updates
    _broadcast_submission_status_change(instance, source, target, user)


def handle_submission_unclaimed(instance, source, target, user, context=None, **kwargs):
    """
    Handle submission unclaim transitions (CLAIMED -> PENDING).

    Called when a moderator releases their claim on a submission.

    Args:
        instance: The submission instance.
        source: The source state.
        target: The target state.
        user: The user who unclaimed.
        context: Optional TransitionContext.
    """
    if source != "CLAIMED" or target != "PENDING":
        return

    logger.info(f"Submission {instance.pk} unclaimed by {user.username if user else 'system'}")

    # Broadcast for real-time dashboard updates
    _broadcast_submission_status_change(instance, source, target, user)


def handle_submission_approved(instance, source, target, user, context=None, **kwargs):
    """
    Handle submission approval transitions.

    Called when an EditSubmission or PhotoSubmission is approved.

    Args:
        instance: The submission instance.
        source: The source state.
        target: The target state.
        user: The user who approved.
        context: Optional TransitionContext.
    """
    if target != "APPROVED":
        return

    logger.info(f"Submission {instance.pk} approved by {user if user else 'system'}")

    # Trigger notification (handled by NotificationCallback)
    # Invalidate cache (handled by CacheInvalidationCallback)

    # Apply the submission changes if applicable
    if hasattr(instance, "apply_changes"):
        try:
            instance.apply_changes()
            logger.info(f"Applied changes for submission {instance.pk}")
        except Exception as e:
            logger.exception(f"Failed to apply changes for submission {instance.pk}: {e}")


def handle_submission_rejected(instance, source, target, user, context=None, **kwargs):
    """
    Handle submission rejection transitions.

    Called when an EditSubmission or PhotoSubmission is rejected.

    Args:
        instance: The submission instance.
        source: The source state.
        target: The target state.
        user: The user who rejected.
        context: Optional TransitionContext.
    """
    if target != "REJECTED":
        return

    reason = context.extra_data.get("reason", "") if context else ""
    logger.info(
        f"Submission {instance.pk} rejected by {user if user else 'system'}" f"{f': {reason}' if reason else ''}"
    )


def handle_submission_escalated(instance, source, target, user, context=None, **kwargs):
    """
    Handle submission escalation transitions.

    Called when an EditSubmission or PhotoSubmission is escalated.

    Args:
        instance: The submission instance.
        source: The source state.
        target: The target state.
        user: The user who escalated.
        context: Optional TransitionContext.
    """
    if target != "ESCALATED":
        return

    reason = context.extra_data.get("reason", "") if context else ""
    logger.info(
        f"Submission {instance.pk} escalated by {user if user else 'system'}" f"{f': {reason}' if reason else ''}"
    )

    # Create escalation task if task system is available
    _create_escalation_task(instance, user, reason)


def handle_report_resolved(instance, source, target, user, context=None, **kwargs):
    """
    Handle moderation report resolution.

    Called when a ModerationReport is resolved.

    Args:
        instance: The ModerationReport instance.
        source: The source state.
        target: The target state.
        user: The user who resolved.
        context: Optional TransitionContext.
    """
    if target != "RESOLVED":
        return

    logger.info(f"ModerationReport {instance.pk} resolved by {user if user else 'system'}")

    # Update related queue items
    _update_related_queue_items(instance, "COMPLETED")


def handle_queue_completed(instance, source, target, user, context=None, **kwargs):
    """
    Handle moderation queue completion.

    Called when a ModerationQueue item is completed.

    Args:
        instance: The ModerationQueue instance.
        source: The source state.
        target: The target state.
        user: The user who completed.
        context: Optional TransitionContext.
    """
    if target != "COMPLETED":
        return

    logger.info(f"ModerationQueue {instance.pk} completed by {user if user else 'system'}")

    # Update moderation statistics
    _update_moderation_stats(instance, user)


def handle_bulk_operation_status(instance, source, target, user, context=None, **kwargs):
    """
    Handle bulk operation status changes.

    Called when a BulkOperation transitions between states.

    Args:
        instance: The BulkOperation instance.
        source: The source state.
        target: The target state.
        user: The user who initiated the change.
        context: Optional TransitionContext.
    """
    logger.info(f"BulkOperation {instance.pk} transitioned: {source} → {target}")

    if target == "COMPLETED":
        _finalize_bulk_operation(instance, success=True)
    elif target == "FAILED":
        _finalize_bulk_operation(instance, success=False)


# Helper functions


def _create_escalation_task(instance, user, reason):
    """Create an escalation task for admin review."""
    try:
        from apps.moderation.models import ModerationQueue

        # Create a queue item for the escalated submission
        ModerationQueue.objects.create(
            content_object=instance,
            priority="HIGH",
            reason=f"Escalated: {reason}" if reason else "Escalated for review",
            created_by=user,
        )
        logger.info(f"Created escalation queue item for submission {instance.pk}")
    except ImportError:
        logger.debug("ModerationQueue model not available")
    except Exception as e:
        logger.warning(f"Failed to create escalation task: {e}")


def _update_related_queue_items(instance, status):
    """Update queue items related to a moderation object."""
    try:
        from django.contrib.contenttypes.models import ContentType

        from apps.moderation.models import ModerationQueue

        content_type = ContentType.objects.get_for_model(type(instance))
        queue_items = ModerationQueue.objects.filter(
            content_type=content_type,
            object_id=instance.pk,
        ).exclude(status=status)

        updated = queue_items.update(status=status)
        if updated:
            logger.info(f"Updated {updated} queue items to {status}")
    except ImportError:
        logger.debug("ModerationQueue model not available")
    except Exception as e:
        logger.warning(f"Failed to update queue items: {e}")


def _update_moderation_stats(instance, user):
    """Update moderation statistics for a user."""
    if not user:
        return

    try:
        # Update user's moderation count if they have a profile
        profile = getattr(user, "profile", None)
        if profile and hasattr(profile, "moderation_count"):
            profile.moderation_count += 1
            profile.save(update_fields=["moderation_count"])
            logger.debug(f"Updated moderation count for {user}")
    except Exception as e:
        logger.warning(f"Failed to update moderation stats: {e}")


def _finalize_bulk_operation(instance, success):
    """Finalize a bulk operation after completion or failure."""
    try:
        from django.utils import timezone

        instance.completed_at = timezone.now()
        instance.save(update_fields=["completed_at"])

        if success:
            logger.info(
                f"BulkOperation {instance.pk} completed successfully: "
                f"{getattr(instance, 'success_count', 0)} succeeded, "
                f"{getattr(instance, 'failure_count', 0)} failed"
            )
        else:
            logger.warning(
                f"BulkOperation {instance.pk} failed: " f"{getattr(instance, 'error_message', 'Unknown error')}"
            )
    except Exception as e:
        logger.warning(f"Failed to finalize bulk operation: {e}")


def _broadcast_submission_status_change(instance, source, target, user):
    """
    Broadcast submission status change for real-time UI updates.

    Emits the submission_status_changed signal with a structured payload
    that can be consumed by notification systems (Novu, SSE, WebSocket, etc.).

    Payload format:
    {
        "submission_id": 123,
        "submission_type": "edit" | "photo",
        "new_status": "CLAIMED",
        "previous_status": "PENDING",
        "locked_by": "moderator_username" | None,
        "locked_at": "2024-01-01T12:00:00Z" | None,
        "changed_by": "username" | None,
    }
    """
    try:
        from .models import EditSubmission

        # Determine submission type
        submission_type = "edit" if isinstance(instance, EditSubmission) else "photo"

        # Build the broadcast payload
        payload = {
            "submission_id": instance.pk,
            "submission_type": submission_type,
            "new_status": target,
            "previous_status": source,
            "locked_by": None,
            "locked_at": None,
            "changed_by": user.username if user else None,
        }

        # Add claim information if available
        if hasattr(instance, "claimed_by") and instance.claimed_by:
            payload["locked_by"] = instance.claimed_by.username
        if hasattr(instance, "claimed_at") and instance.claimed_at:
            payload["locked_at"] = instance.claimed_at.isoformat()

        # Emit the signal for downstream notification handlers
        submission_status_changed.send(
            sender=type(instance),
            submission_id=instance.pk,
            submission_type=submission_type,
            new_status=target,
            previous_status=source,
            locked_by=payload["locked_by"],
            payload=payload,
        )

        logger.debug(f"Broadcast status change: {submission_type}#{instance.pk} " f"{source} -> {target}")
    except Exception as e:
        logger.warning(f"Failed to broadcast submission status change: {e}")


# Signal handler registration


def register_moderation_signal_handlers():
    """
    Register all moderation signal handlers.

    This function should be called in the moderation app's AppConfig.ready() method.
    """
    from apps.core.state_machine.signals import register_transition_handler

    try:
        from apps.moderation.models import (
            BulkOperation,
            EditSubmission,
            ModerationQueue,
            ModerationReport,
            PhotoSubmission,
        )

        # EditSubmission handlers
        register_transition_handler(EditSubmission, "*", "APPROVED", handle_submission_approved, stage="post")
        register_transition_handler(EditSubmission, "*", "REJECTED", handle_submission_rejected, stage="post")
        register_transition_handler(EditSubmission, "*", "ESCALATED", handle_submission_escalated, stage="post")

        # PhotoSubmission handlers
        register_transition_handler(PhotoSubmission, "*", "APPROVED", handle_submission_approved, stage="post")
        register_transition_handler(PhotoSubmission, "*", "REJECTED", handle_submission_rejected, stage="post")
        register_transition_handler(PhotoSubmission, "*", "ESCALATED", handle_submission_escalated, stage="post")

        # ModerationReport handlers
        register_transition_handler(ModerationReport, "*", "RESOLVED", handle_report_resolved, stage="post")

        # ModerationQueue handlers
        register_transition_handler(ModerationQueue, "*", "COMPLETED", handle_queue_completed, stage="post")

        # BulkOperation handlers
        register_transition_handler(BulkOperation, "*", "*", handle_bulk_operation_status, stage="post")

        # Claim/Unclaim handlers for EditSubmission
        register_transition_handler(EditSubmission, "PENDING", "CLAIMED", handle_submission_claimed, stage="post")
        register_transition_handler(EditSubmission, "CLAIMED", "PENDING", handle_submission_unclaimed, stage="post")

        # Claim/Unclaim handlers for PhotoSubmission
        register_transition_handler(PhotoSubmission, "PENDING", "CLAIMED", handle_submission_claimed, stage="post")
        register_transition_handler(PhotoSubmission, "CLAIMED", "PENDING", handle_submission_unclaimed, stage="post")

        logger.info("Registered moderation signal handlers")

    except ImportError as e:
        logger.warning(f"Could not register moderation signal handlers: {e}")


__all__ = [
    "submission_status_changed",
    "register_moderation_signal_handlers",
    "handle_submission_approved",
    "handle_submission_rejected",
    "handle_submission_escalated",
    "handle_submission_claimed",
    "handle_submission_unclaimed",
    "handle_report_resolved",
    "handle_queue_completed",
    "handle_bulk_operation_status",
]
