from django.utils import timezone
from rest_framework import serializers
from rest_framework.relations import SlugRelatedField

from files.models import File
from inventory.models import Event, Container, Item, Comment
from inventory.shared_serializers import BasicItemSerializer
from mail.models import EventAddress
from tickets.shared_serializers import BasicIssueSerializer


class EventSerializer(serializers.ModelSerializer):
    addresses = SlugRelatedField(many=True, slug_field='address', queryset=EventAddress.objects.all())

    class Meta:
        model = Event
        fields = ['id', 'slug', 'name', 'start', 'end', 'pre_start', 'post_end', 'addresses']
        read_only_fields = ['id']

    def to_internal_value(self, data):
        data = data.copy()
        addresses = data.pop('addresses', None)
        dict = super().to_internal_value(data)
        if addresses:
            dict['addresses'] = [EventAddress.objects.get_or_create(address=x)[0] for x in addresses]
        return dict


class ContainerSerializer(serializers.ModelSerializer):
    itemCount = serializers.SerializerMethodField()

    class Meta:
        model = Container
        fields = ['id', 'name', 'itemCount']
        read_only_fields = ['id', 'itemCount']

    def get_itemCount(self, instance):
        return len(instance.items)


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', 'item')


class ItemSerializer(BasicItemSerializer):
    timeline = serializers.SerializerMethodField()
    dataImage = serializers.CharField(write_only=True, required=False)
    related_issues = BasicIssueSerializer(many=True, read_only=True)

    class Meta:
        model = Item
        fields = ['cid', 'box', 'id', 'description', 'file', 'dataImage', 'returned', 'event', 'related_issues',
                  'timeline']
        read_only_fields = ['id']
        prefetch_related_fields = ['comments', 'issue_relation_changes', 'container_history',
                                   'container_history__container', 'files', 'event',
                                   'issue_relation_changes__issue_thread',
                                   'issue_relation_changes__issue_thread__event',
                                   'issue_relation_changes__issue_thread__state_changes',
                                   'issue_relation_changes__issue_thread__assignments']

    def to_internal_value(self, data):
        container = None
        returned = False
        if 'cid' in data:
            container = Container.objects.get(id=data['cid'])
        if 'returned' in data:
            returned = data['returned']
        internal = super().to_internal_value(data)
        if container:
            internal['container'] = container
        if returned:
            internal['returned_at'] = timezone.now()
        return internal

    def validate(self, attrs):
        if not 'container' in attrs and not self.partial:
            raise serializers.ValidationError("This field cannot be empty.")
        return super().validate(attrs)

    def create(self, validated_data):
        if 'dataImage' in validated_data:
            file = File.objects.create(data=validated_data['dataImage'])
            validated_data.pop('dataImage')
            item = Item.objects.create(**validated_data)
            item.files.set([file])
            return item
        return Item.objects.create(**validated_data)

    def update(self, instance, validated_data):
        if 'returned' in validated_data:
            if validated_data['returned']:
                validated_data['returned_at'] = timezone.now()
            validated_data.pop('returned')
        if 'dataImage' in validated_data:
            file = File.objects.create(data=validated_data['dataImage'])
            validated_data.pop('dataImage')
            instance.files.add(file)
        return super().update(instance, validated_data)

    @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 relation in (obj.issue_relation_changes.all()):
            timeline.append({
                'type': 'issue_relation',
                'id': relation.id,
                'status': relation.status,
                'timestamp': relation.timestamp,
                'issue_thread': BasicIssueSerializer(relation.issue_thread).data,
            })
        for placement in (obj.container_history.all()):
            timeline.append({
                'type': 'placement',
                'id': placement.id,
                'timestamp': placement.timestamp,
                'cid': placement.container.id,
                'box': placement.container.name
            })
        return sorted(timeline, key=lambda x: x['timestamp'])


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

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

    class Meta:
        model = Item