from __future__ import unicode_literals

from .models import Message
from .signals import message_read, message_sent
from django.core.exceptions import ValidationError
from django.utils import timezone
from django.db.models import Q


class MessagingService(object):
    """
    A object to manage all messages and conversations
    """

    # Message creation

    def send_message(self, sender, sender_user, recipient, message, quote_id):
        """
        Send a new message
        :param sender: company
        :param sender_user: user
        :param recipient: company
        :param message: String
        :return: Message and status code
        """

        if sender == recipient:
            raise ValidationError("You can't send messages to yourself.")

        message = Message(sender=sender, sender_user=sender_user, recipient=recipient, content=str(message),
                          title=quote_id)
        message.save()

        message_sent.send(sender=message, from_user=message.sender, to=message.recipient)

        # The second value acts as a status value
        return message, 200

    # Message reading
    def get_unread_messages(self, user):
        """
        List of unread messages for a specific user
        :param user: user
        :return: messages
        """
        return Message.objects.all().filter(recipient=user, read_at=None)

    def read_message(self, message_id):
        """
        Read specific message
        :param message_id: Integer
        :return: Message Text
        """
        try:
            message = Message.objects.get(id=message_id)
            self.mark_as_read(message)
            return message.content
        except Message.DoesNotExist:
            return ""

    def read_message_formatted(self, message_id):
        """
        Read a message in the format <User>: <Message>
        :param message_id: Id
        :return: Formatted Message Text
        """
        try:
            message = Message.objects.get(id=message_id)
            self.mark_as_read(message)
            return message.sender.username + ": "+message.content
        except Message.DoesNotExist:
            return ""

    # Conversation management

    def get_conversations(self, user):
        """
        Lists all conversation-partners for a specific user
        :param user: User
        :return: Conversation list
        """
        all_conversations = Message.objects.all().filter(Q(sender=user) | Q(recipient=user))

        contacts = []
        for conversation in all_conversations:
            if conversation.sender != user:
                contacts.append(conversation.sender)
            elif conversation.recipient != user:
                contacts.append(conversation.recipient)

        # To abolish duplicates
        return list(set(contacts))

    def get_conversation(self, company1, company2, quote_id, limit=None, reversed=False, mark_read=False):
        """
        List of messages between two users
        :param company1: User
        :param company2: User
        :param quote_id: Title
        :param limit: int
        :param reversed: Boolean - Makes the newest message be at index 0
        :return: messages
        """
        companys = [company1, company2]

        # Newest message first if it's reversed (index 0)
        if reversed:
            order = '-pk'
        else:
            order = 'pk'

        conversation = Message.objects.all().filter(
            sender__in=companys,
            recipient__in=companys,
            title=quote_id).order_by(order)

        if limit:
            # Limit number of messages to the x newest
            conversation = conversation[:limit]

        if mark_read:
            for message in conversation:
                # Just to be sure, everything is read
                self.mark_as_read(message)

        return conversation

    # Helper methods
    def mark_as_read(self, message):
        """
        Marks a message as read, if it hasn't been read before
        :param message: Message
        """

        if message.read_at is None:
            message.read_at = timezone.now()
            message_read.send(sender=message, from_user=message.sender, to=message.recipient)
            message.save()

