from django.db import models
from django.contrib import admin
from django.contrib.auth.models import User as DjangoUser
from django.core.exceptions import ValidationError

from datetime import datetime


ALKATOR_CHOICES = (
    (1, "Alkátor"),
    (2, "Alkátor light"),
    (3, "Nealkátor"),
)


ALKATOR_CLASSES = (
    (1, "Jaro 2024 Sobkovice"),
    (2, "Podzim 2024 Studené"),
    (3, "Jaro 2025 Dolní Čermná")
)


ALKATOR_CHOICES_DICT = {
    alkator_choice[0]: alkator_choice[1]
    for alkator_choice in ALKATOR_CHOICES
}


ALKATOR_CLASSES_DICT = {
    alkator_class[0]: alkator_class[1]
    for alkator_class in ALKATOR_CLASSES
}


class User(models.Model):
    first_name = models.CharField(max_length=120)
    last_name = models.CharField(max_length=120)
    address = models.CharField(max_length=255, null=True, blank=True)
    email = models.EmailField(max_length=120, null=True, blank=True)
    phone = models.CharField(max_length=120, null=True, blank=True)
    date_of_birth = models.DateField(null=True, blank=True)
    register_date = models.DateTimeField(auto_now=True)
    duration = models.DurationField(null=True, blank=True)
    starting_number = models.IntegerField(null=True, blank=True)
    alkator_category = models.IntegerField(choices=ALKATOR_CHOICES, default=1)
    alkator_class = models.IntegerField(choices=ALKATOR_CLASSES)
    trans_id = models.CharField(null=True, blank=True, max_length=120)
    price = models.IntegerField(default=690)
    paid = models.BooleanField(default=False)
    invoice_id = models.IntegerField(null=True, blank=True, unique=True)

    def __str__(self):
        return f"<User {self.starting_number} {self.first_name} {self.last_name} {self.email} {self.duration} {ALKATOR_CHOICES_DICT[self.alkator_category]} {ALKATOR_CLASSES_DICT[self.alkator_class]} {self.paid}>"


class Profile(models.Model):
    user = models.OneToOneField(DjangoUser, related_name='profile', on_delete=models.CASCADE)
    first_name = models.CharField(max_length=120)
    last_name = models.CharField(max_length=120)
    phone = models.CharField(max_length=120, null=True, blank=True)
    address = models.CharField(max_length=255, null=True, blank=True)

    def __str__(self):
        return f"<Profile {self.user.email} {self.first_name} {self.last_name}>"


class Product(models.Model):
    name = models.CharField(max_length=120)
    description = models.TextField()
    img = models.ImageField(upload_to="photos")
    price = models.IntegerField()
    hidden = models.BooleanField(default=False)
    quantity = models.IntegerField()

    def __str__(self):
        return f"<Product {self.name} {self.price} Kč zbývá {self.quantity}>"


class Cart(models.Model):
    user = models.OneToOneField(DjangoUser, on_delete=models.RESTRICT, related_name='cart')
    items = models.ManyToManyField(Product, through='CartProduct')
    address = models.CharField(max_length=120, null=True, blank=True)


class CartProduct(models.Model):
    product = models.ForeignKey(Product, on_delete=models.RESTRICT)
    cart = models.ForeignKey('Cart', on_delete=models.CASCADE)
    class Meta:
        unique_together = ('product', 'cart')
    quantity = models.IntegerField()

    def clean(self):
        data = self.cleaned_data
        if data['quantity'] <= 0:
            raise ValidationError("Počet předmětů v košíku musí být kladný!")


class Invoice(models.Model):
    invoice_id = models.IntegerField(unique=True)
    user = models.ForeignKey(DjangoUser, on_delete=models.RESTRICT)
    items = models.ManyToManyField(Product, through='InvoiceProduct')
    total_price = models.IntegerField()
    paid_date = models.DateTimeField(auto_now=True)
    paid = models.BooleanField(default=False)
    trans_id = models.CharField(null=True, blank=True, max_length=120)
    address = models.CharField(max_length=255, null=True, blank=True)

    @classmethod
    def next_invoice_id(cls):
        invoice_date = datetime.today()
        invoice_id = invoice_date.year * 1000000 + invoice_date.month * 10000 + invoice_date.day * 100

        try:
            latest_invoice = cls.objects.latest("invoice_id")
            if latest_invoice.invoice_id is None or latest_invoice.invoice_id < invoice_id:
                invoice_id = invoice_id + 1
            else:
                invoice_id = latest_invoice.invoice_id + 1
        except Invoice.DoesNotExist:
            invoice_id = invoice_id + 1
        return invoice_id

    def calculate_total_price(self):
        total_price = 0
        for item in InvoiceProduct.objects.filter(invoice=self):
            total_price += item.price * item.quantity
        return total_price


class InvoiceProduct(models.Model):
    product = models.ForeignKey(Product, on_delete=models.RESTRICT)
    invoice = models.ForeignKey(Invoice, on_delete=models.RESTRICT)
    class Meta:
        unique_together = ('product', 'invoice')
    quantity = models.IntegerField()
    price = models.IntegerField(default=1)

    def clean(self):
        data = self.cleaned_data
        if data['quantity'] <= 0:
            raise ValidationError("Počet předmětů ve faktuře musí být kladný!")

    def __str__(self):
        return f"<InvoiceProduct {self.product.name} {self.invoice.invoice_id} *{self.quantity}"


class Racer(InvoiceProduct):
    profile = models.ForeignKey(Profile, related_name='racers', on_delete=models.RESTRICT)
    first_name = models.CharField(max_length=120)
    last_name = models.CharField(max_length=120)
    email = models.EmailField(max_length=120, null=True, blank=True)
    team = models.CharField(max_length=120, null=True, blank=True)
    phone = models.CharField(max_length=120, null=True, blank=True)
    date_of_birth = models.DateField(null=True, blank=True)
    duration = models.DurationField(null=True, blank=True)
    starting_number = models.IntegerField(null=True, blank=True)
    alkator_category = models.IntegerField(choices=ALKATOR_CHOICES, default=1)
    alkator_class = models.IntegerField(choices=ALKATOR_CLASSES)

    def clean(self):
        super(self).clean()
        data = self.cleaned_data
        if data['quantity'] != 1:
            raise ValidationError("Počet přihlášek v jedné objednávce musí být právě 1!")

    def __str__(self):
        return f"<Racer {self.email} {self.first_name} {self.last_name} {self.team}>"
