from django.conf import settings
from django.db.models.signals import post_save, pre_save
from django.dispatch import receiver
from django.utils import timezone

from core.models import Profile, Listing, Message, Notification, Review, InquiryRequest, Event, EventTicketOrder


@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_profile_for_new_user(sender, instance, created, **kwargs):
    """Every user gets a Profile automatically — discoverer by default, lister on demand."""
    if created:
        Profile.objects.get_or_create(user=instance)


@receiver(pre_save, sender=Profile)
def stamp_verified_at(sender, instance, **kwargs):
    """Record the moment a profile becomes verified, and notify the user of KYC status changes."""
    if not instance.pk:
        return
    try:
        previous = Profile.objects.get(pk=instance.pk)
    except Profile.DoesNotExist:
        return

    if previous.verification_status != instance.verification_status:
        if instance.verification_status == Profile.VERIFIED and not instance.verified_at:
            instance.verified_at = timezone.now()

        Notification.objects.create(
            user=instance.user,
            notification_type=Notification.TYPE_KYC_STATUS,
            title="Your verification status has changed",
            body=f"Your account is now: {instance.get_verification_status_display()}.",
            link="/accounts/profile/",
        )


@receiver(pre_save, sender=Listing)
def stamp_listing_verification_and_notify_status(sender, instance, **kwargs):
    """
    Mirror the lister's current KYC status onto the listing, and notify the
    lister whenever moderators change a listing's status.
    """
    instance.is_verified_listing = getattr(
        getattr(instance.lister, "profile", None), "verification_status", None
    ) == Profile.VERIFIED

    if instance.pk:
        try:
            previous = Listing.objects.get(pk=instance.pk)
        except Listing.DoesNotExist:
            previous = None
        if previous and previous.status != instance.status:
            Notification.objects.create(
                user=instance.lister,
                notification_type=Notification.TYPE_LISTING_STATUS,
                title=f"Listing status updated: {instance.title}",
                body=f"Your listing is now '{instance.get_status_display()}'.",
                link=f"/listings/{instance.slug}/" if instance.slug else "",
            )
        # Price drop detection for saved searches (simple, synchronous demo version)
        if previous and instance.price and previous.price and instance.price < previous.price:
            _notify_price_drop(instance)


def _notify_price_drop(listing):
    from core.models import SavedSearch

    matches = SavedSearch.objects.filter(is_active=True, category=listing.category)
    for search in matches:
        if search.max_price and listing.price > search.max_price:
            continue
        Notification.objects.create(
            user=search.user,
            notification_type=Notification.TYPE_PRICE_DROP,
            title=f"Price drop: {listing.title}",
            body=f"Now {listing.currency} {listing.price:,.0f}",
            link=f"/listings/{listing.slug}/",
        )


@receiver(post_save, sender=Message)
def notify_new_message(sender, instance, created, **kwargs):
    if not created:
        return
    conversation = instance.conversation
    for participant in conversation.participants.exclude(pk=instance.sender_id):
        Notification.objects.create(
            user=participant,
            notification_type=Notification.TYPE_NEW_MESSAGE,
            title=f"New message from {instance.sender.get_full_name() or instance.sender.username}",
            body=instance.body[:120],
            link=f"/messages/{conversation.pk}/",
        )


@receiver(post_save, sender=Review)
def notify_review_created_or_replied(sender, instance, created, **kwargs):
    if created:
        Notification.objects.create(
            user=instance.listing.lister,
            notification_type=Notification.TYPE_REVIEW_REPLY,
            title=f"New review on {instance.listing.title}",
            body=f"{instance.rating}★ from {instance.reviewer.username}",
            link=f"/listings/{instance.listing.slug}/",
        )
    elif instance.lister_reply:
        Notification.objects.create(
            user=instance.reviewer,
            notification_type=Notification.TYPE_REVIEW_REPLY,
            title=f"{instance.listing.lister.username} replied to your review",
            body=instance.lister_reply[:120],
            link=f"/listings/{instance.listing.slug}/",
        )


@receiver(post_save, sender=InquiryRequest)
def notify_new_inquiry(sender, instance, created, **kwargs):
    if created:
        Notification.objects.create(
            user=instance.listing.lister,
            notification_type=Notification.TYPE_INQUIRY,
            title=f"New inquiry on {instance.listing.title}",
            body=(instance.message or "")[:120],
            link=f"/listings/{instance.listing.slug}/",
        )


@receiver(pre_save, sender=Event)
def stamp_event_verification_and_notify_status(sender, instance, **kwargs):
    """
    Mirror the organizer's current KYC status onto the event, and notify the
    organizer whenever moderators change an event's status — mirrors the
    same pattern used for Listing above.
    """
    instance.is_verified_event = getattr(
        getattr(instance.organizer, "profile", None), "verification_status", None
    ) == Profile.VERIFIED

    if instance.pk:
        try:
            previous = Event.objects.get(pk=instance.pk)
        except Event.DoesNotExist:
            previous = None
        if previous and previous.status != instance.status:
            Notification.objects.create(
                user=instance.organizer,
                notification_type=Notification.TYPE_EVENT_STATUS,
                title=f"Event status updated: {instance.title}",
                body=f"Your event is now '{instance.get_status_display()}'.",
                link=f"/events/{instance.slug}/" if instance.slug else "",
            )


@receiver(post_save, sender=EventTicketOrder)
def notify_new_ticket_order(sender, instance, created, **kwargs):
    if not created:
        return
    Notification.objects.create(
        user=instance.event.organizer,
        notification_type=Notification.TYPE_TICKET_BOOKED,
        title=f"New booking: {instance.event.title}",
        body=f"{instance.quantity}x {instance.ticket_type.name} booked by "
             f"{instance.buyer.get_full_name() or instance.buyer.username}.",
        link=f"/events/{instance.event.slug}/",
    )
    Notification.objects.create(
        user=instance.buyer,
        notification_type=Notification.TYPE_TICKET_BOOKED,
        title=f"Booking confirmed: {instance.event.title}",
        body=f"{instance.quantity}x {instance.ticket_type.name} — Ref {instance.reference_code}",
        link=f"/events/{instance.event.slug}/",
    )