from django.conf import settings
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models


class Course(models.Model):
    """Disciplina (ex.: Cálculo II)."""

    name = models.CharField("nome", max_length=200)
    code = models.CharField("código", max_length=50, unique=True, blank=True)
    description = models.TextField("descrição", blank=True)
    is_active = models.BooleanField("ativa", default=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name = "disciplina"
        verbose_name_plural = "disciplinas"
        ordering = ["name"]

    def __str__(self):
        return self.name


class Topic(models.Model):
    """Tópico de uma disciplina (ex.: Integração por partes)."""

    course = models.ForeignKey(
        Course, on_delete=models.CASCADE, related_name="topics", verbose_name="disciplina"
    )
    parent = models.ForeignKey(
        "self",
        on_delete=models.CASCADE,
        related_name="children",
        null=True,
        blank=True,
        verbose_name="tópico pai",
    )
    name = models.CharField("nome", max_length=200)
    description = models.TextField("descrição", blank=True)
    order = models.PositiveIntegerField("ordem", default=0)
    prerequisites = models.ManyToManyField(
        "self",
        symmetrical=False,
        blank=True,
        related_name="dependent_topics",
        verbose_name="pré-requisitos",
    )
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name = "tópico"
        verbose_name_plural = "tópicos"
        ordering = ["course", "order", "name"]
        constraints = [
            models.UniqueConstraint(
                fields=["course", "name"], name="unique_topic_course_name"
            )
        ]

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


class Class(models.Model):
    """Turma (unidade comercial e ambiente de validação do Learning Engine)."""

    class Mode(models.TextChoices):
        IN_PERSON = "in_person", "Presencial"
        ONLINE = "online", "Online"
        HYBRID = "hybrid", "Híbrido"

    name = models.CharField("nome", max_length=200)
    course = models.ForeignKey(
        Course, on_delete=models.PROTECT, related_name="classes", verbose_name="disciplina"
    )
    instructor = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.PROTECT,
        related_name="instructor_classes",
        limit_choices_to={"role": "instructor"},
        verbose_name="formador",
    )
    description = models.TextField("descrição", blank=True)
    schedule = models.CharField("horário", max_length=200, blank=True)
    mode = models.CharField(
        "modalidade", max_length=20, choices=Mode.choices, default=Mode.IN_PERSON
    )
    location_or_link = models.CharField("local ou link", max_length=300, blank=True)
    max_capacity = models.PositiveIntegerField("capacidade máxima", default=0)
    price = models.DecimalField(
        "preço", max_digits=10, decimal_places=2, default=0
    )
    start_date = models.DateField("início", null=True, blank=True)
    end_date = models.DateField("fim", null=True, blank=True)
    community_link = models.URLField("link da comunidade", blank=True)
    is_active = models.BooleanField("ativa", default=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name = "turma"
        verbose_name_plural = "turmas"
        ordering = ["-created_at"]

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

    @property
    def is_paid(self) -> bool:
        return self.price > 0

    @property
    def active_enrollments(self) -> int:
        return self.enrollments.filter(status=Enrollment.Status.ACTIVE).count()

    @property
    def available_slots(self) -> int:
        if self.max_capacity <= 0:
            return -1  # ilimitado
        return max(0, self.max_capacity - self.active_enrollments)


class Enrollment(models.Model):
    """Inscrição de um estudante numa turma."""

    class Status(models.TextChoices):
        PENDING = "pending", "Pendente"
        ACTIVE = "active", "Ativa"
        CANCELLED = "cancelled", "Cancelada"
        COMPLETED = "completed", "Concluída"

    student = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="enrollments",
        verbose_name="estudante",
    )
    klass = models.ForeignKey(
        Class,
        on_delete=models.CASCADE,
        related_name="enrollments",
        verbose_name="turma",
    )
    status = models.CharField(
        "estado", max_length=20, choices=Status.choices, default=Status.PENDING
    )
    enrolled_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        verbose_name = "inscrição"
        verbose_name_plural = "inscrições"
        ordering = ["-enrolled_at"]
        constraints = [
            models.UniqueConstraint(
                fields=["student", "klass"], name="unique_student_class"
            )
        ]

    def __str__(self):
        return f"{self.student} — {self.klass} ({self.status})"


class Event(models.Model):
    """Evento (aulas gratuitas, aulões, workshops, sessões de preparação...)."""

    class Mode(models.TextChoices):
        IN_PERSON = "in_person", "Presencial"
        ONLINE = "online", "Online"

    class Status(models.TextChoices):
        PENDING = "pending", "Pendente"
        ACTIVE = "active", "Ativo"
        CANCELLED = "cancelled", "Cancelado"
        COMPLETED = "completed", "Concluído"

    title = models.CharField("título", max_length=200)
    description = models.TextField("descrição", blank=True)
    instructor = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        related_name="events",
        null=True,
        blank=True,
        limit_choices_to={"role": "instructor"},
        verbose_name="formador",
    )
    date = models.DateField("data")
    time = models.TimeField("hora", null=True, blank=True)
    mode = models.CharField(
        "modalidade", max_length=20, choices=Mode.choices, default=Mode.ONLINE
    )
    location_or_link = models.CharField("local ou link", max_length=300, blank=True)
    max_capacity = models.PositiveIntegerField("capacidade máxima", default=0)
    status = models.CharField(
        "estado", max_length=20, choices=Status.choices, default=Status.ACTIVE
    )
    requirements = models.TextField("requisitos", blank=True)
    allow_guest_enrollment = models.BooleanField(
        "permitir inscrição sem conta", default=True
    )
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name = "evento"
        verbose_name_plural = "eventos"
        ordering = ["date"]

    def __str__(self):
        return self.title

    @property
    def active_enrollments(self) -> int:
        return self.event_enrollments.filter(status=EventEnrollment.Status.ACTIVE).count()

    @property
    def available_slots(self) -> int:
        if self.max_capacity <= 0:
            return -1
        return max(0, self.max_capacity - self.active_enrollments)


class EventEnrollment(models.Model):
    """Inscrição num evento (com ou sem conta)."""

    class Status(models.TextChoices):
        ACTIVE = "active", "Ativa"
        CANCELLED = "cancelled", "Cancelada"
        COMPLETED = "completed", "Concluída"

    event = models.ForeignKey(
        Event, on_delete=models.CASCADE, related_name="event_enrollments", verbose_name="evento"
    )
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="event_enrollments",
        null=True,
        blank=True,
        verbose_name="utilizador",
    )
    guest_name = models.CharField("nome do convidado", max_length=200, blank=True)
    guest_phone = models.CharField("telefone do convidado", max_length=20, blank=True)
    status = models.CharField(
        "estado", max_length=20, choices=Status.choices, default=Status.ACTIVE
    )
    enrolled_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name = "inscrição em evento"
        verbose_name_plural = "inscrições em eventos"
        ordering = ["-enrolled_at"]

    def __str__(self):
        name = self.guest_name or str(self.user)
        return f"{name} — {self.event.title}"


class Payment(models.Model):
    """Pagamento associado a uma inscrição (confirmação manual no MVP)."""

    class Method(models.TextChoices):
        TRANSFER = "transfer", "Transferência"
        CASH = "cash", "Dinheiro"
        CARD = "card", "Cartão"
        OTHER = "other", "Outro"

    class Status(models.TextChoices):
        PENDING = "pending", "Pendente"
        PAID = "paid", "Pago"
        REJECTED = "rejected", "Rejeitado"
        REFUNDED = "refunded", "Reembolsado"

    enrollment = models.OneToOneField(
        Enrollment, on_delete=models.CASCADE, related_name="payment", verbose_name="inscrição"
    )
    amount = models.DecimalField("valor", max_digits=10, decimal_places=2)
    method = models.CharField(
        "método", max_length=20, choices=Method.choices, default=Method.TRANSFER
    )
    date = models.DateField("data", auto_now_add=True)
    reference = models.CharField("referência", max_length=100, blank=True)
    status = models.CharField(
        "estado", max_length=20, choices=Status.choices, default=Status.PENDING
    )
    confirmed_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        related_name="confirmed_payments",
        null=True,
        blank=True,
        verbose_name="confirmado por",
    )
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name = "pagamento"
        verbose_name_plural = "pagamentos"
        ordering = ["-created_at"]

    def __str__(self):
        return f"{self.enrollment} — {self.status}"


class Material(models.Model):
    """Material/biblioteca (PDF, resumo, vídeo, prova anterior...)."""

    class Type(models.TextChoices):
        PDF = "pdf", "PDF"
        BOOK = "book", "Livro"
        SUMMARY = "summary", "Resumo"
        VIDEO = "video", "Vídeo"
        LINK = "link", "Link"
        PAST_EXAM = "past_exam", "Prova anterior"
        OTHER = "other", "Outro"

    title = models.CharField("título", max_length=200)
    material_type = models.CharField(
        "tipo", max_length=20, choices=Type.choices, default=Type.PDF
    )
    course = models.ForeignKey(
        Course,
        on_delete=models.CASCADE,
        related_name="materials",
        null=True,
        blank=True,
        verbose_name="disciplina",
    )
    topic = models.ForeignKey(
        Topic,
        on_delete=models.SET_NULL,
        related_name="materials",
        null=True,
        blank=True,
        verbose_name="tópico",
    )
    klass = models.ForeignKey(
        Class,
        on_delete=models.SET_NULL,
        related_name="materials",
        null=True,
        blank=True,
        verbose_name="turma",
    )
    file = models.FileField("ficheiro", upload_to="materials/", blank=True)
    url = models.URLField("link", blank=True)
    description = models.TextField("descrição", blank=True)
    is_public = models.BooleanField("público", default=False)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name = "material"
        verbose_name_plural = "materiais"
        ordering = ["-created_at"]

    def __str__(self):
        return self.title
