import datetime

from django.db.models import QuerySet
from django.shortcuts import get_object_or_404
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import generics
from rest_framework import permissions
from rest_framework.exceptions import ValidationError
from rest_framework.filters import SearchFilter, OrderingFilter
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response

from . import models, serializers, filters, tasks


class SettingDetail(generics.RetrieveUpdateAPIView):
    """
    获得设置
    更新设置
    """
    queryset = models.Setting.objects.all()
    serializer_class = serializers.SettingSerializer
    permission_classes = (permissions.IsAdminUser,)


class Room(generics.ListAPIView):
    """
    获得room列表
    """
    queryset = models.Room.objects.all().order_by('name')
    serializer_class = serializers.RoomSerializer
    permission_classes = (permissions.IsAuthenticated,)


class RoomDetail(generics.RetrieveUpdateAPIView):
    """
    获得指定room
    更新指定room
    """
    queryset = models.Room.objects.all()
    serializer_class = serializers.RoomSerializer
    permission_classes = (permissions.IsAdminUser,)


class Seat(generics.ListCreateAPIView):
    """
    获得seat列表
    新建seat
    """
    queryset = models.Seat.objects.all().order_by('-created_datetime')
    serializer_class = serializers.SeatSerializer
    permission_classes = (permissions.IsAdminUser,)
    filter_backends = (DjangoFilterBackend,)
    filterset_fields = ['room__id']

    def perform_create(self, serializer):
        name = serializer.validated_data.get('name')
        r = serializer.validated_data.get('room')
        room = models.Room.objects.get(id=r.id)
        models.Seat.objects.create(room=room, name=name)


class SeatDetail(generics.DestroyAPIView):
    """
    删除指定seat
    """
    queryset = models.Seat.objects.all()
    serializer_class = serializers.SeatSerializer
    permission_classes = (permissions.IsAdminUser,)


class Booking(generics.ListCreateAPIView):
    """
    获得booking列表
    新建booking
    """
    queryset = models.Booking.objects.all().order_by('id')
    # serializer_class = serializers.BookingSerializer
    permission_classes = (permissions.IsAuthenticated,)
    pagination_class = PageNumberPagination
    filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter)
    filterset_class = filters.BookingFilter
    search_fields = [
        'id',
        'user__username',
        'room__name',
        'date'
    ]
    ordering_fields = [
        'id',
        'date',
        'start_time',
        'end_time',
    ]

    def perform_create(self, serializer):
        data = serializer.validated_data
        start_time = data['start_time']
        end_time = data['end_time']
        setting = models.Setting.objects.get(id=1)
        if start_time < setting.start_time or start_time > setting.end_time:
            raise ValidationError(f'开始时间无效，应该在[{setting.start_time} - {setting.end_time}]之间。')
        if end_time < setting.start_time or end_time > setting.end_time:
            raise ValidationError(f'结束时间无效，应该在[{setting.start_time} - {setting.end_time}]之间。')
        serializer.save()
        tasks.createBooking.delay(serializer.data)

    def get_serializer_class(self):
        if self.request.stream and self.request.stream.method == 'POST':
            return serializers.BookingCreateSerializer
        else:
            return serializers.BookingSerializer


class BookingDetail(generics.RetrieveUpdateDestroyAPIView):
    """
    获得指定booking
    更新指定booking
    删除指定booking
    """
    queryset = models.Booking.objects.all()
    serializer_class = serializers.BookingSerializer
    permission_classes = (permissions.IsAuthenticated,)


class BookingStatusList(generics.GenericAPIView):
    """
    获得预约状态列表
    """
    queryset = QuerySet()
    permission_classes = (permissions.IsAuthenticated,)

    def get(self, request):
        status_list = []
        for status in models.Booking.STATUS_CHIOCE:
            status_list.append({
                'id': status[0],
                'name': status[1]
            })
        return Response(status_list)


class BookingCancel(generics.GenericAPIView):
    """
    取消预约
    """
    serializer_class = serializers.BookingCancelSerializer
    permission_classes = (permissions.IsAdminUser,)

    def post(self, request, pk):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        booking = self.get_queryset()
        booking.status = 'CANCELED'
        booking.cancel_by = request.user
        booking.cancel_datetime = datetime.datetime.now()
        booking.cancel_reason = serializer.validated_data['cancel_reason']
        booking.save()
        return Response(serializer.validated_data)

    def get_queryset(self):
        return models.Booking.objects.get(id=self.kwargs['pk'])


class RoomBookingStatus(generics.GenericAPIView):
    """
    获得房间预约信息
    """
    queryset = QuerySet()
    serializer_class = (serializers.RoomSerializer)
    permission_classes = (permissions.IsAuthenticated,)

    def get(self, request):
        try:
            date = datetime.datetime.strptime(request.query_params.get('date'), '%Y-%m-%d').date()
        except Exception as e:
            raise ValidationError(e)
        setting = models.Setting.objects.get(id=1)
        start_datetime = datetime.datetime.combine(date, setting.start_time)
        end_datetime = datetime.datetime.combine(date, setting.end_time)
        step = datetime.timedelta(minutes=setting.booking_interval)
        count_per_seat = int((end_datetime - start_datetime) / step)
        count_total = 0
        booked_count_total = 0
        booking_count_total = 0
        room_booking_status_list = []
        for room in models.Room.objects.all():
            seat_list = room.seat_set.all()
            count_per_room = 0
            booked_count = 0
            booking_count = 0
            for seat in seat_list:
                count_per_room += count_per_seat
                booking_list = models.Booking.objects.filter(date=date, room=room, seats__id=seat.id, status='SUCCESS')
                for booking in booking_list:
                    s_datetime = datetime.datetime.combine(date, booking.start_time)
                    e_datetime = datetime.datetime.combine(date, booking.end_time)
                    s = int((s_datetime - start_datetime) / step)
                    e = int((e_datetime - start_datetime) / step)
                    booked_count += e - s
                    booking_count += 1
            count_total += count_per_room
            booked_count_total += booked_count
            booking_count_total += booking_count
            room_booking_status_list.append({
                **self.get_serializer(room).data,
                'count': count_per_room,
                'booked_count': booked_count,
                'booking_count': booking_count
            })
        return Response({
            'count_total': count_total,
            'booked_count_total': booked_count_total,
            'booking_count_total': booking_count_total,
            'results': room_booking_status_list
        })


class RoomBookingStatusDetail(generics.GenericAPIView):
    """
    获得指定房间的预约信息
    """
    queryset = QuerySet()
    serializer_class = (serializers.RoomSerializer)
    permission_classes = (permissions.IsAuthenticated,)

    def get(self, request, pk):
        try:
            date = datetime.datetime.strptime(request.query_params.get('date'), '%Y-%m-%d').date()
        except Exception as e:
            raise ValidationError(e)
        room = get_object_or_404(models.Room, id=pk)
        setting = models.Setting.objects.get(id=1)
        count_total = 0
        booked_count_total = 0
        seat_list = []
        for seat in room.seat_set.all():
            # 初始化数组
            step = datetime.timedelta(minutes=setting.booking_interval)
            booking_status_list = []
            start_datetime = datetime.datetime.combine(date, setting.start_time)
            end_datetime = start_datetime + step
            while end_datetime <= datetime.datetime.combine(date, setting.end_time):
                booking_status_list.append({
                    'start_time': start_datetime.strftime('%H:%M:%S'),
                    'end_time': end_datetime.strftime('%H:%M:%S'),
                    'booking': None
                })
                count_total += 1
                start_datetime = end_datetime
                end_datetime += step
            # 检查预约记录
            for booking in models.Booking.objects.filter(date=date, room=room, seats__id=seat.id, status='SUCCESS'):
                s_datetime = datetime.datetime.combine(date, booking.start_time)
                e_datetime = datetime.datetime.combine(date, booking.end_time)
                s = int((s_datetime - start_datetime) / step)
                e = int((e_datetime - start_datetime) / step)
                booked_count_total += e - s
                for i in range(s, e):
                    booking_status_list[i]['booking'] = serializers.BookingSerializer(booking).data
            seat_list.append({
                'id': seat.id,
                'name': seat.name,
                'booking_status_list': booking_status_list
            })
        return Response({
            **self.get_serializer(room).data,
            'date': date,
            'count_total': count_total,
            'booked_count_total': booked_count_total,
            'seat_list': seat_list
        })
