from rest_framework import serializers

from authentication.models import ExtendedUser
from inventory.models import Event
from inventory.shared_serializers import BasicItemSerializer
from mail.api_v2 import AttachmentSerializer
from tickets.models import IssueThread, Comment, STATE_CHOICES, ShippingVoucher
from tickets.shared_serializers import BasicIssueSerializer


class CommentSerializer(serializers.ModelSerializer):

    def validate(self, attrs):
        if 'comment' not in attrs or attrs['comment'] == '':
            raise serializers.ValidationError('comment cannot be empty')
        return attrs

    class Meta:
        model = Comment
        fields = ('id', 'comment', 'timestamp', 'issue_thread')


class StateSerializer(serializers.Serializer):
    text = serializers.SerializerMethodField()
    value = serializers.SerializerMethodField()

    def get_text(self, obj):
        return obj['text']

    def get_value(self, obj):
        return obj['value']


class ShippingVoucherSerializer(serializers.ModelSerializer):
    class Meta:
        model = ShippingVoucher
        fields = ('id', 'voucher', 'type', 'timestamp', 'issue_thread', 'used_at')
        read_only_fields = ('id', 'timestamp', 'used_at')


class IssueSerializer(BasicIssueSerializer):
    timeline = serializers.SerializerMethodField()
    last_activity = serializers.SerializerMethodField()
    related_items = BasicItemSerializer(many=True, read_only=True)

    class Meta:
        model = IssueThread
        fields = ('id', 'timeline', 'name', 'state', 'assigned_to', 'last_activity', 'uuid', 'related_items', 'event')
        read_only_fields = ('id', 'timeline', 'last_activity', 'uuid', 'related_items')
        prefetch_related_fields = ['state_changes', 'comments', 'emails', 'emails__attachments', 'assignments',
                                   'item_relation_changes', 'shipping_vouchers', 'item_relation_changes__item',
                                   'item_relation_changes__item__container_history', 'event',
                                   'item_relation_changes__item__container_history__container',
                                   'item_relation_changes__item__files', 'item_relation_changes__item__event',
                                   'item_relation_changes__item__event']

    def to_internal_value(self, data):
        ret = super().to_internal_value(data)
        if 'state' in data:
            ret['state'] = data['state']
        return ret

    def validate(self, attrs):
        if 'state' in attrs:
            if attrs['state'] not in [x[0] for x in STATE_CHOICES]:
                raise serializers.ValidationError('invalid state')
        return attrs

    @staticmethod
    def get_last_activity(self):
        try:
            last_state_change = max(
                [t.timestamp for t in self.state_changes.all()]) if self.state_changes.exists() else None
            last_comment = max([t.timestamp for t in self.comments.all()]) if self.comments.exists() else None
            last_mail = max([t.timestamp for t in self.emails.all()]) if self.emails.exists() else None
            last_assignment = max([t.timestamp for t in self.assignments.all()]) if self.assignments.exists() else None

            last_relation = max([t.timestamp for t in
                                 self.item_relation_changes.all()]) if self.item_relation_changes.exists() else None
            args = [x for x in [last_state_change, last_comment, last_mail, last_assignment, last_relation] if
                    x is not None]
            return max(args)
        except AttributeError:
            return None

    @staticmethod
    def get_timeline(obj):
        timeline = []
        for comment in obj.comments.all():
            timeline.append({
                'type': 'comment',
                'id': comment.id,
                'timestamp': comment.timestamp,
                'comment': comment.comment,
            })
        for state_change in obj.state_changes.all():
            timeline.append({
                'type': 'state',
                'id': state_change.id,
                'timestamp': state_change.timestamp,
                'state': state_change.state,
            })
        for email in obj.emails.all():
            timeline.append({
                'type': 'mail',
                'id': email.id,
                'timestamp': email.timestamp,
                'sender': email.sender,
                'recipient': email.recipient,
                'subject': email.subject,
                'body': email.body,
                'attachments': AttachmentSerializer(email.attachments.all(), many=True).data,
            })
        for assignment in obj.assignments.all():
            timeline.append({
                'type': 'assignment',
                'id': assignment.id,
                'timestamp': assignment.timestamp,
                'assigned_to': assignment.assigned_to.username,
            })
        for relation in (obj.item_relation_changes.all()):
            timeline.append({
                'type': 'item_relation',
                'id': relation.id,
                'status': relation.status,
                'timestamp': relation.timestamp,
                'item': BasicItemSerializer(relation.item).data,
            })
        for shipping_voucher in obj.shipping_vouchers.all():
            timeline.append({
                'type': 'shipping_voucher',
                'id': shipping_voucher.id,
                'timestamp': shipping_voucher.used_at,
                'voucher': shipping_voucher.voucher,
                'voucher_type': shipping_voucher.type,
            })
        return sorted(timeline, key=lambda x: x['timestamp'])


class SearchResultSerializer(serializers.Serializer):
    search_score = serializers.IntegerField()
    item = IssueSerializer()

    def to_representation(self, instance):
        return {**IssueSerializer(instance['item']).data, 'search_score': instance['search_score']}

    class Meta:
        model = IssueThread