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

from core.models import TimeStampedModel


class SupportTicket(TimeStampedModel):
    class Category(models.TextChoices):
        BILLING = "billing", "Faturação / pagamento"
        DOMAIN = "domain", "Domínio"
        HOSTING = "hosting", "Alojamento"
        EMAIL = "email", "Email"
        WEBSITE = "website", "Website"
        TECHNICAL = "technical", "Questão técnica"
        CHANGE = "change", "Pedido de alteração"
        OTHER = "other", "Outro"

    class Priority(models.TextChoices):
        LOW = "low", "Baixa"
        NORMAL = "normal", "Normal"
        HIGH = "high", "Alta"
        URGENT = "urgent", "Urgente"

    class Status(models.TextChoices):
        OPEN = "open", "Aberto"
        IN_PROGRESS = "in_progress", "Em tratamento"
        REOPENED = "reopened", "Reaberto"
        WAITING_CLIENT = "waiting_client", "A aguardar cliente"
        WAITING_INTERNAL = "waiting_internal", "A aguardar internamente"
        RESOLVED = "resolved", "Resolvido"
        CLOSED = "closed", "Fechado"

    class Channel(models.TextChoices):
        PORTAL = "portal", "Portal do cliente"
        EMAIL = "email", "Email"
        PHONE = "phone", "Telefone"
        INTERNAL = "internal", "Registo interno"

    client = models.ForeignKey(
        "clients.Client",
        on_delete=models.PROTECT,
        related_name="support_tickets",
        verbose_name="Cliente",
    )
    service = models.ForeignKey(
        "services.Service",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="support_tickets",
        verbose_name="Serviço",
    )
    subject = models.CharField("Assunto", max_length=220)
    category = models.CharField("Categoria", max_length=25, choices=Category.choices, default=Category.OTHER)
    priority = models.CharField("Prioridade", max_length=15, choices=Priority.choices, default=Priority.NORMAL, db_index=True)
    status = models.CharField("Estado", max_length=25, choices=Status.choices, default=Status.OPEN, db_index=True)
    channel = models.CharField("Origem", max_length=20, choices=Channel.choices, default=Channel.INTERNAL)
    assigned_to = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="assigned_support_tickets",
        verbose_name="Responsável",
    )
    description = models.TextField("Descrição")
    due_date = models.DateField("Data limite", null=True, blank=True, db_index=True)
    last_activity_at = models.DateTimeField("Última atividade", default=timezone.now, db_index=True)
    closed_at = models.DateTimeField("Fechado em", null=True, blank=True)
    client_visible = models.BooleanField(
        "Visível no portal do cliente",
        default=True,
        help_text="Quando ativo, o ticket e as mensagens públicas ficam disponíveis na área do cliente.",
    )
    client_last_read_at = models.DateTimeField("Lido pelo cliente em", null=True, blank=True)
    staff_last_read_at = models.DateTimeField("Lido pela equipa em", null=True, blank=True)
    resolved_by_client = models.BooleanField("Resolvido pelo cliente", default=False)
    resolved_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="resolved_support_tickets",
        verbose_name="Resolvido por",
    )
    resolution_note = models.TextField("Nota de resolução", blank=True)

    class Meta:
        verbose_name = "Pedido de suporte"
        verbose_name_plural = "Pedidos de suporte"
        ordering = ["status", "-priority", "-last_activity_at"]
        indexes = [
            models.Index(fields=["status", "priority", "last_activity_at"]),
            models.Index(fields=["client", "status"]),
        ]

    @property
    def is_overdue(self):
        return bool(
            self.due_date
            and self.status not in {self.Status.RESOLVED, self.Status.CLOSED}
            and self.due_date < timezone.localdate()
        )

    def save(self, *args, **kwargs):
        if self.status in {self.Status.RESOLVED, self.Status.CLOSED} and not self.closed_at:
            self.closed_at = timezone.now()
        elif self.status not in {self.Status.RESOLVED, self.Status.CLOSED}:
            self.closed_at = None
        super().save(*args, **kwargs)

    @property
    def reference(self):
        return f"K4W-{self.pk:06d}" if self.pk else "K4W-NOVO"

    @property
    def unread_for_client(self):
        return self.messages.filter(
            author_type=SupportMessage.AuthorType.STAFF,
            is_internal=False,
            read_by_client_at__isnull=True,
        ).count()

    @property
    def unread_for_staff(self):
        return self.messages.filter(
            author_type=SupportMessage.AuthorType.CLIENT,
            read_by_staff_at__isnull=True,
        ).count()

    def mark_resolved(self, *, user=None, by_client=False, note=""):
        now = timezone.now()
        self.status = self.Status.RESOLVED
        self.closed_at = now
        self.last_activity_at = now
        self.resolved_by_client = by_client
        self.resolved_by = None if by_client else user
        if note:
            self.resolution_note = note
        self.save(update_fields=[
            "status", "closed_at", "resolved_by_client", "resolved_by",
            "resolution_note", "last_activity_at", "updated_at"
        ])

    def reopen(self):
        self.status = self.Status.REOPENED
        self.closed_at = None
        self.resolved_by_client = False
        self.resolved_by = None
        self.last_activity_at = timezone.now()
        self.save(update_fields=[
            "status", "closed_at", "resolved_by_client", "resolved_by",
            "last_activity_at", "updated_at"
        ])

    def __str__(self):
        return f"{self.reference} — {self.subject}"


class SupportMessage(TimeStampedModel):
    class AuthorType(models.TextChoices):
        STAFF = "staff", "Equipa"
        CLIENT = "client", "Cliente"
        SYSTEM = "system", "Sistema"

    ticket = models.ForeignKey(
        SupportTicket,
        on_delete=models.CASCADE,
        related_name="messages",
        verbose_name="Pedido",
    )
    author_type = models.CharField("Autor", max_length=15, choices=AuthorType.choices, default=AuthorType.STAFF)
    staff_user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="support_messages",
        verbose_name="Utilizador interno",
    )
    author_name = models.CharField("Nome apresentado", max_length=180, blank=True)
    author_email = models.EmailField("Email", blank=True)
    message = models.TextField("Mensagem")
    is_internal = models.BooleanField(
        "Nota interna",
        default=False,
        help_text="As notas internas nunca são apresentadas ao cliente.",
    )
    attachment = models.FileField("Anexo", upload_to="support/%Y/%m/", blank=True)
    read_by_client_at = models.DateTimeField("Lida pelo cliente em", null=True, blank=True)
    read_by_staff_at = models.DateTimeField("Lida pela equipa em", null=True, blank=True)

    class Meta:
        verbose_name = "Mensagem de suporte"
        verbose_name_plural = "Mensagens de suporte"
        ordering = ["created_at"]

    def save(self, *args, **kwargs):
        creating = self._state.adding
        super().save(*args, **kwargs)
        if not creating:
            return
        now = self.created_at or timezone.now()
        updates = {"last_activity_at": now}
        if self.author_type == self.AuthorType.CLIENT:
            updates.update({"status": SupportTicket.Status.WAITING_INTERNAL, "closed_at": None, "resolved_by_client": False})
        elif self.author_type == self.AuthorType.STAFF and not self.is_internal:
            updates.update({"status": SupportTicket.Status.WAITING_CLIENT, "closed_at": None})
        SupportTicket.objects.filter(pk=self.ticket_id).update(**updates)

    def __str__(self):
        return f"{self.ticket} — {self.get_author_type_display()}"
