import logging

from mission.notifications import enqueue_mission_created_speech
from mission.payload_processors import apply_mission_payload_processor
from notifier.models import NotificationEventKeyEnum
from notifier.services import enqueue_notification_event

logger = logging.getLogger(__name__)


def _build_mission_payload(mission) -> dict:
    participant_names = list(
        mission.get_participants().values_list("employee__name", flat=True)
    )
    content_type = getattr(mission.content_type, "model", None)
    return {
        "mission_id": mission.id,
        "merchant_id": mission.merchant_id,
        "description": mission.description,
        "category_id": mission.category_id,
        "category_name": mission.category.name,
        "is_urgent": mission.is_urgent,
        "is_completed": mission.is_completed,
        "is_cancelled": mission.is_cancelled,
        "creator_id": mission.creator_id,
        "creator_name": getattr(mission.creator, "name", ""),
        "participant_names": participant_names,
        "participant_names_display": "、".join(participant_names) if participant_names else "无",
        "content_type": content_type or "",
        "content_id": mission.content_id or "",
        "payload_processor": getattr(mission.category, "payload_processor", "") or "",
    }


def _build_reply_payload(reply) -> dict:
    return {
        "reply_id": reply.id,
        "reply_content": reply.content,
        "reply_content_short": (reply.content or "")[:100],
        "responder_id": reply.responder_id,
        "responder_name": getattr(reply.responder, "name", ""),
        "ends_task": reply.ends_task,
        "is_rejected": reply.is_rejected,
        "replied_at": reply.replied_at.isoformat() if reply.replied_at else "",
        "rejected_at": reply.rejected_at.isoformat() if reply.rejected_at else "",
    }


def _enqueue(*, event_key: str, merchant_id: int, payload: dict) -> None:
    task_id = enqueue_notification_event(
        event_key=event_key,
        merchant_id=merchant_id,
        payload=payload,
    )
    logger.info(
        "[mission.handlers] queued notifier event: event_key=%s merchant_id=%s task_id=%s",
        event_key,
        merchant_id,
        task_id,
    )


def on_mission_created(sender, instance, created_by=None, **kwargs):
    payload = apply_mission_payload_processor(
        mission=instance,
        event_key=NotificationEventKeyEnum.MISSION_CREATED,
        payload={
            **_build_mission_payload(instance),
            "created_by_id": getattr(created_by, "id", None),
            "created_by_name": getattr(created_by, "name", ""),
        },
    )
    _enqueue(
        event_key=NotificationEventKeyEnum.MISSION_CREATED,
        merchant_id=instance.merchant_id,
        payload=payload,
    )
    enqueue_mission_created_speech(mission=instance)


def on_mission_replied(sender, instance, mission=None, responder=None, **kwargs):
    mission = mission or instance.mission
    payload = apply_mission_payload_processor(
        mission=mission,
        event_key=NotificationEventKeyEnum.MISSION_REPLIED,
        payload={
            **_build_mission_payload(mission),
            **_build_reply_payload(instance),
            "responder_id": getattr(responder, "id", None),
            "responder_name": getattr(responder, "name", ""),
        },
    )
    _enqueue(
        event_key=NotificationEventKeyEnum.MISSION_REPLIED,
        merchant_id=mission.merchant_id,
        payload=payload,
    )


def on_mission_completed(sender, instance, completed_by=None, reply=None, **kwargs):
    payload = {
        **_build_mission_payload(instance),
        "completed_by_id": getattr(completed_by, "id", None),
        "completed_by_name": getattr(completed_by, "name", ""),
    }
    if reply is not None:
        payload.update(_build_reply_payload(reply))
    payload = apply_mission_payload_processor(
        mission=instance,
        event_key=NotificationEventKeyEnum.MISSION_COMPLETED,
        payload=payload,
    )
    _enqueue(
        event_key=NotificationEventKeyEnum.MISSION_COMPLETED,
        merchant_id=instance.merchant_id,
        payload=payload,
    )


def on_mission_reply_rejected(sender, instance, mission=None, rejected_by=None, reason=None, **kwargs):
    mission = mission or instance.mission
    payload = apply_mission_payload_processor(
        mission=mission,
        event_key=NotificationEventKeyEnum.MISSION_REPLY_REJECTED,
        payload={
            **_build_mission_payload(mission),
            **_build_reply_payload(instance),
            "rejected_by_id": getattr(rejected_by, "id", None),
            "rejected_by_name": getattr(rejected_by, "name", ""),
            "reason": reason or "",
        },
    )
    _enqueue(
        event_key=NotificationEventKeyEnum.MISSION_REPLY_REJECTED,
        merchant_id=mission.merchant_id,
        payload=payload,
    )


def on_mission_reopened(sender, instance, reopened_by=None, rejected_reply_ids=None, **kwargs):
    payload = apply_mission_payload_processor(
        mission=instance,
        event_key=NotificationEventKeyEnum.MISSION_REOPENED,
        payload={
            **_build_mission_payload(instance),
            "reopened_by_id": getattr(reopened_by, "id", None),
            "reopened_by_name": getattr(reopened_by, "name", ""),
            "rejected_reply_ids": rejected_reply_ids or [],
            "rejected_reply_ids_display": ", ".join(str(reply_id) for reply_id in (rejected_reply_ids or [])) or "无",
        },
    )
    _enqueue(
        event_key=NotificationEventKeyEnum.MISSION_REOPENED,
        merchant_id=instance.merchant_id,
        payload=payload,
    )


def on_mission_cancelled(sender, instance, cancelled_by=None, **kwargs):
    payload = apply_mission_payload_processor(
        mission=instance,
        event_key=NotificationEventKeyEnum.MISSION_CANCELLED,
        payload={
            **_build_mission_payload(instance),
            "cancelled_by_id": getattr(cancelled_by, "id", None),
            "cancelled_by_name": getattr(cancelled_by, "name", ""),
            "cancelled_at": instance.cancelled_at.isoformat() if instance.cancelled_at else "",
        },
    )
    _enqueue(
        event_key=NotificationEventKeyEnum.MISSION_CANCELLED,
        merchant_id=instance.merchant_id,
        payload=payload,
    )
