from django.utils import timezone
from django.urls import re_path
from rest_framework import routers, viewsets, serializers
from rest_framework.decorators import api_view, permission_classes, authentication_classes
from rest_framework.response import Response

from files.models import File
from inventory.models import Event, Container, Item
from inventory.serializers import EventSerializer, ContainerSerializer


class EventViewSet(viewsets.ModelViewSet):
    serializer_class = EventSerializer
    queryset = Event.objects.all()
    permission_classes = []
    authentication_classes = []


class ContainerViewSet(viewsets.ModelViewSet):
    serializer_class = ContainerSerializer
    queryset = Container.objects.all()
    permission_classes = []
    authentication_classes = []


class ItemSerializer(serializers.ModelSerializer):
    dataImage = serializers.CharField(write_only=True, required=False)
    cid = serializers.SerializerMethodField()
    box = serializers.SerializerMethodField()
    file = serializers.SerializerMethodField()

    class Meta:
        model = Item
        fields = ['cid', 'box', 'uid', 'description', 'file', 'dataImage']
        read_only_fields = ['uid']

    def get_cid(self, instance):
        return instance.container.cid

    def get_box(self, instance):
        return instance.container.name

    def get_file(self, instance):
        if len(instance.files.all()) > 0:
            return instance.files.all().order_by('-created_at')[0].hash
        return None

    def to_internal_value(self, data):
        if 'cid' in data:
            container = Container.objects.get(cid=data['cid'])
            internal = super().to_internal_value(data)
            internal['container'] = container
            return internal
        return super().to_internal_value(data)

    def validate(self, attrs):
        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)


@api_view(['GET'])
@permission_classes([])
@authentication_classes([])
def search_items(request, event_slug, query):
    try:
        event = Event.objects.get(slug=event_slug)
        query_tokens = query.split(' ')
        q = Item.objects.filter(event=event)
        for token in query_tokens:
            if token:
                q = q.filter(description__icontains=token)
        return Response(ItemSerializer(q, many=True).data)
    except Event.DoesNotExist:
        return Response(status=404)


@api_view(['GET', 'POST'])
@permission_classes([])
@authentication_classes([])
def item(request, event_slug):
    try:
        event = Event.objects.get(slug=event_slug)
        if request.method == 'GET':
            return Response(ItemSerializer(Item.objects.filter(event=event), many=True).data)
        elif request.method == 'POST':
            validated_data = ItemSerializer(data=request.data)
            if validated_data.is_valid():
                validated_data.save(event=event)
                return Response(validated_data.data, status=201)
    except Event.DoesNotExist:
        return Response(status=404)


@api_view(['GET', 'PUT', 'DELETE'])
@permission_classes([])
@authentication_classes([])
def item_by_id(request, event_slug, id):
    try:
        event = Event.objects.get(slug=event_slug)
        item = Item.objects.get(event=event, uid=id)
        if request.method == 'GET':
            return Response(ItemSerializer(item).data)
        elif request.method == 'PUT':
            validated_data = ItemSerializer(item, data=request.data)
            if validated_data.is_valid():
                validated_data.save()
                return Response(validated_data.data)
        elif request.method == 'DELETE':
            item.delete()
            return Response(status=204)
    except Item.DoesNotExist:
        return Response(status=404)
    except Event.DoesNotExist:
        return Response(status=404)


urlpatterns = [
    re_path('events/?$', EventViewSet.as_view({'get': 'list', 'post': 'create'})),
    re_path('events/(?P<pk>[0-9]+)/?$',
            EventViewSet.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
    re_path('boxes/?$', ContainerViewSet.as_view({'get': 'list', 'post': 'create'})),
    re_path('boxes/(?P<pk>[0-9]+)/?$',
            ContainerViewSet.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
    re_path('box/?$', ContainerViewSet.as_view({'get': 'list', 'post': 'create'})),
    re_path('box/(?P<pk>[0-9]+)/?$',
            ContainerViewSet.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
    re_path('(?P<event_slug>[a-zA-Z0-9]+)/items/?$', item),
    re_path('(?P<event_slug>[a-zA-Z0-9]+)/items/(?P<query>[^/]+)/?$', search_items),
    re_path('(?P<event_slug>[a-zA-Z0-9]+)/item/?$', item),
    re_path('(?P<event_slug>[a-zA-Z0-9]+)/item/(?P<id>[0-9]+)/?$', item_by_id),
]