import random
import string
from uuid import uuid4

from django.db import models
from django.utils import timezone


def generate_isbn() -> str:
    """
    Generate a random ISBN number.

    Returns:
        A 13-digit string.

    """
    digits = string.digits
    return "".join(random.choice(digits) for _ in range(13))


class BookQuerySet(models.QuerySet):
    """
    QuerySet class for books.

    """

    def available(self) -> models.QuerySet:
        """
        Get books available for a loan.

        Excludes books with at least a loan whose `borrowed` field is `True`.
        Given the constraints, only one loan for a book can have the `borrowed` status
        to `True`.

        """
        return self.exclude(loans__borrowed=True)

    def late_returns(self) -> models.QuerySet:
        """
        Get books that should have been returned by now.

        """
        now = timezone.now()
        return self.filter(loans__expected_return__lt=now, borrowed=True)


class Book(models.Model):
    """
    Description of a book.

    """

    uuid = models.UUIDField(default=uuid4, db_index=True, verbose_name="UUID")
    isbn = models.CharField(max_length=64, default=generate_isbn, blank=False, verbose_name="ISBN")
    name = models.CharField(max_length=128, blank=False, verbose_name="name")
    description = models.TextField(blank=True, verbose_name="description")
    registration_date = models.DateTimeField(auto_now_add=True, verbose_name="creation date")
    year = models.PositiveIntegerField(default=1950, null=True, db_index=True, verbose_name="published")
    authors = models.ManyToManyField("library.Author", related_name="books", verbose_name="authors")
    genre = models.ForeignKey(
        "library.Genre", on_delete=models.SET_NULL, null=True, related_name="books", verbose_name="genre"
    )
    objects = BookQuerySet.as_manager()

    class Meta:
        verbose_name = "book"
        verbose_name_plural = "books"

    def __str__(self):
        return f"{self.name} ({self.isbn})"
