from rest_framework import serializers

from authentication.models import ExtendedUser
from mail.api_v2 import AttachmentSerializer
from tickets.models import IssueThread, Comment, STATE_CHOICES, ShippingVoucher
from inventory.serializers import ItemSerializer


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(serializers.ModelSerializer):
    timeline = serializers.SerializerMethodField()
    last_activity = serializers.SerializerMethodField()
    assigned_to = serializers.SlugRelatedField(slug_field='username', queryset=ExtendedUser.objects.all(),
                                               allow_null=True, required=False)
    related_items = ItemSerializer(many=True, read_only=True)

    class Meta:
        model = IssueThread
        fields = ('id', 'timeline', 'name', 'state', 'assigned_to', 'last_activity', 'uuid', 'related_items')
        read_only_fields = ('id', 'timeline', 'last_activity', 'uuid', 'related_items')

    def to_internal_value(self, data):
        ret = super().to_internal_value(data)
        if 'state' in data:
            ret['state'] = data['state']
#        if 'assigned_to' in data:
#            ret['assigned_to'] = data['assigned_to']
        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 = self.state_changes.order_by('-timestamp').first().timestamp \
                if self.state_changes.count() > 0 else None
            last_comment = self.comments.order_by('-timestamp').first().timestamp if self.comments.count() > 0 else None
            last_mail = self.emails.order_by('-timestamp').first().timestamp if self.emails.count() > 0 else None
            last_assignment = self.assignments.order_by('-timestamp').first().timestamp if \
                self.assignments.count() > 0 else None
            last_relation = self.item_relations.order_by('-timestamp').first().timestamp if \
                self.item_relations.count() > 0 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_relations.all():
            timeline.append({
                'type': 'item_relation',
                'id': relation.id,
                'status': relation.status,
                'timestamp': relation.timestamp,
                'item': ItemSerializer(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'])

    def get_queryset(self):
        return IssueThread.objects.all().order_by('-last_activity')