"""
Chat permission and business logic services.
"""
from follows.models import FollowUser


def can_message_user(sender, recipient) -> tuple[bool, str]:
    """
    Check if sender can message recipient.

    Rule: Recipient must be following sender. This ensures that users
    can only be messaged by people they have chosen to follow.

    Args:
        sender: The user attempting to send a message
        recipient: The user who would receive the message

    Returns:
        tuple: (can_message: bool, error_message: str)
    """
    if sender == recipient:
        return False, "Vous ne pouvez pas vous envoyer un message à vous-même."

    from users.models import BlockedUser

    # Check if sender is blocked by recipient
    if BlockedUser.objects.filter(blocker=recipient, blocked=sender).exists():
        return False, "Vous ne pouvez pas envoyer de message à cet utilisateur car il vous a bloqué."

    # Check if sender has blocked recipient
    if BlockedUser.objects.filter(blocker=sender, blocked=recipient).exists():
        return False, "Vous ne pouvez pas envoyer de message à cet utilisateur car vous l'avez bloqué."

    return True, ""


def get_or_create_conversation(initiator, recipient, create_if_not_exists=True):
    """
    Get existing conversation between two users.
    Optionally create a new one as an unaccepted invitation.

    Args:
        initiator: The user starting/finding the conversation
        recipient: The other user
        create_if_not_exists: Whether to create a new one if not found

    Returns:
        tuple: (conversation, created: bool)
    """
    from chat.models import Conversation, ConversationVisibility

    # Find existing 1-on-1 conversation with both participants (exclude groups)
    conversation = Conversation.objects.filter(
        participants=initiator,
        is_group=False
    ).filter(
        participants=recipient
    ).first()

    if conversation:
        # Ensure visibility is restored for the initiator
        ConversationVisibility.objects.update_or_create(
            user=initiator,
            conversation=conversation,
            defaults={'is_visible': True}
        )

        # Restore visibility for recipient as well (so they see the chat if initiator messages again)
        ConversationVisibility.objects.update_or_create(
            user=recipient,
            conversation=conversation,
            defaults={'is_visible': True}
        )

        return conversation, False

    if not create_if_not_exists:
        return None, False

    # New conversations always start as NOT accepted invitations
    conversation = Conversation.objects.create(
        is_accepted=False,
        initiator=initiator
    )
    conversation.participants.add(initiator, recipient)

    # Visibility for both
    ConversationVisibility.objects.update_or_create(
        user=initiator,
        conversation=conversation,
        defaults={'is_visible': True}
    )
    ConversationVisibility.objects.update_or_create(
        user=recipient,
        conversation=conversation,
        defaults={'is_visible': True}
    )

    return conversation, True


def hide_conversation_for_user(user, conversation):
    """
    Hide a conversation for a specific user (soft delete).

    Args:
        user: The user hiding the conversation
        conversation: The conversation to hide
    """
    from chat.models import ConversationVisibility
    from django.utils import timezone

    visibility, _ = ConversationVisibility.objects.get_or_create(
        user=user,
        conversation=conversation
    )
    visibility.is_visible = False
    # We do NOT set hidden_until because "Hide" should just be an archive function.
    # We do NOT delete messages.
    visibility.save()


def delete_conversation_for_user(user, conversation):
    """
    Delete a conversation for a specific user (clear history and hide).

    Args:
        user: The user deleting the conversation
        conversation: The conversation to delete
    """
    from chat.models import ConversationVisibility
    from django.utils import timezone

    visibility, _ = ConversationVisibility.objects.get_or_create(
        user=user,
        conversation=conversation
    )
    visibility.is_visible = False
    visibility.hidden_until = timezone.now()
    visibility.save()


def mark_messages_as_read(user, conversation):
    """
    Mark all unread messages in a conversation as read for a user.

    Args:
        user: The user reading the messages
        conversation: The conversation containing the messages
    """
    from chat.models import Message, MessageRead

    # Get messages that haven't been read by this user yet
    # For 1-on-1, we can also check the legacy is_read field
    unread_query = Message.objects.filter(
        conversation=conversation
    ).exclude(
        sender=user
    ).exclude(
        read_by__user=user
    )

    messages_to_mark = list(unread_query)

    if not messages_to_mark:
        return

    # Create MessageRead records for this user
    read_records = [
        MessageRead(message=msg, user=user)
        for msg in messages_to_mark
    ]
    MessageRead.objects.bulk_create(read_records, ignore_conflicts=True)

    # For 1-on-1 conversations, also update the legacy is_read field for simplicity
    if not conversation.is_group:
        Message.objects.filter(
            id__in=[msg.id for msg in messages_to_mark]
        ).update(is_read=True)


def ensure_visibility_on_new_message(conversation, sender):
    """
    Ensure the conversation is visible to all participants when a new message is sent.
    This ensures that if a user hid or 'deleted' (cleared history) a conversation,
    it reappears once a new message is received.
    """
    from chat.models import ConversationVisibility

    # Set is_visible=True for all participants
    ConversationVisibility.objects.filter(
        conversation=conversation
    ).update(is_visible=True)
