from django.db import models
from django.db.models import Q
from django.urls import reverse
from django.utils import timezone

from app.base.forms.fields import DateTimeField, TextField

from datetime import datetime
from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from django.db.models import OuterRef
    from app.base.models.person import Person
    from app.base.models.booking_type import BookingType


class Booking(models.Model):
    type: 'models.ForeignKey[BookingType]' = models.ForeignKey(
        'BookingType', on_delete=models.PROTECT, verbose_name='Art')
    user: 'models.ForeignKey[Person]' = models.ForeignKey(
        'Person', on_delete=models.CASCADE, verbose_name='Nutzer:in')
    begin_time = DateTimeField('Beginn', default=datetime.now)
    end_time = DateTimeField('Ende', blank=True, null=True)
    comment = TextField('Kommentar', blank=True)

    class Meta:
        verbose_name = 'Buchung'
        verbose_name_plural = 'Buchungen'

    def get_absolute_url(self):
        return reverse('booking:detail', kwargs={'pk': self.pk})

    def __str__(self):
        return 'Buchung von {} am {}: {}-{} Uhr'.format(
            self.user,
            self.begin_time.strftime('%d.%m.%Y'),
            self.begin_time.strftime('%H:%M'),
            self.end_time.strftime('%H:%M') if self.end_time else '')

    @property
    def duration(self) -> 'int|None':
        if self.end_time:
            return round((self.end_time - self.begin_time).seconds / 60)
        return None

    @property
    def calculated_price(self):
        traits = self.user.traits_at_date(self.begin_time).values_list('trait')
        traits = set(x[0] for x in traits)
        return self.type.price_with_traits(self.duration or 0, traits)

    @staticmethod
    def latest_checkin_query(for_user: 'Person|OuterRef'):
        objects = Booking.objects.filter(user=for_user)
        return objects.order_by('-begin_time').values('begin_time')[:1]

    @staticmethod
    def currently_open_checkin(for_user: 'Person|OuterRef') -> 'Booking|None':
        return Booking.objects.filter(
            Q(user=for_user),
            Q(begin_time__lte=timezone.now()),
            Q(end_time=None),
            Q(type__is_checkin=True)
        ).first()
