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

from core.models import TimeStampedModel


class NotificationTemplate(TimeStampedModel):
    class Type(models.TextChoices):
        RENEWAL_30 = "renewal_30", "Renovação — 30 dias"
        RENEWAL_15 = "renewal_15", "Renovação — 15 dias"
        RENEWAL_7 = "renewal_7", "Renovação — 7 dias"
        DUE = "due", "No dia da renovação"
        OVERDUE = "overdue", "Serviço vencido"
        PAYMENT_RECEIVED = "payment_received", "Confirmação de pagamento"
        RENEWAL_CONFIRMED = "renewal_confirmed", "Confirmação de renovação"
        GENERAL = "general", "Mensagem geral"
        SUPPORT_CREATED = "support_created", "Ticket criado"
        SUPPORT_REPLY = "support_reply", "Nova resposta de suporte"
        SUPPORT_RESOLVED = "support_resolved", "Ticket resolvido"
        MONITOR_DOWN = "monitor_down", "Website indisponível"
        MONITOR_RECOVERED = "monitor_recovered", "Website recuperado"

    code = models.SlugField("Código", max_length=80, unique=True)
    notification_type = models.CharField("Tipo", max_length=30, choices=Type.choices, db_index=True)
    subject_template = models.CharField("Assunto", max_length=250)
    body_template = models.TextField(
        "Mensagem em texto",
        help_text=(
            "Variáveis: {cliente}, {servico}, {dominio}, {data_renovacao}, {valor}, "
            "{metodo_pagamento}, {empresa}, {email_empresa}, {telefone_empresa}, {mbway}, {iban}, "
            "{website}, {url}, {motivo}."
        ),
    )
    html_body_template = models.TextField(
        "Mensagem HTML",
        blank=True,
        help_text="Versão HTML opcional. Se ficar vazia, é criada uma versão simples a partir do texto.",
    )
    allow_automatic_send = models.BooleanField(
        "Permitir envio automático",
        default=True,
        help_text="Quando desativado, a automação cria apenas um rascunho para revisão.",
    )
    send_to_billing_contacts = models.BooleanField(
        "Incluir contactos financeiros",
        default=True,
        help_text="Adiciona em CC os contactos do cliente marcados para receber avisos financeiros.",
    )
    is_active = models.BooleanField("Ativo", default=True)

    class Meta:
        verbose_name = "Modelo de notificação"
        verbose_name_plural = "Modelos de notificação"
        ordering = ["notification_type", "code"]

    def __str__(self):
        return self.code


class EmailSuppression(TimeStampedModel):
    class Reason(models.TextChoices):
        INVALID = "invalid", "Endereço inválido"
        BOUNCED = "bounced", "Email devolvido"
        REQUESTED = "requested", "Pedido do destinatário"
        SECURITY = "security", "Bloqueio de segurança"
        OTHER = "other", "Outro"

    email = models.EmailField("Email", unique=True, db_index=True)
    reason = models.CharField("Motivo", max_length=20, choices=Reason.choices, default=Reason.OTHER)
    description = models.TextField("Descrição", blank=True)
    is_active = models.BooleanField("Bloqueio ativo", default=True, db_index=True)

    class Meta:
        verbose_name = "Email bloqueado"
        verbose_name_plural = "Emails bloqueados"
        ordering = ["email"]

    def __str__(self):
        return self.email


class NotificationLog(TimeStampedModel):
    class Channel(models.TextChoices):
        EMAIL = "email", "Email"
        SMS = "sms", "SMS"
        INTERNAL = "internal", "Alerta interno"
        PORTAL = "portal", "Portal do cliente"

    class Status(models.TextChoices):
        DRAFT = "draft", "Rascunho"
        SCHEDULED = "scheduled", "Agendado"
        SENDING = "sending", "A enviar"
        SENT = "sent", "Enviado"
        FAILED = "failed", "Falhou"
        CANCELLED = "cancelled", "Cancelado"
        SUPPRESSED = "suppressed", "Bloqueado"

    class DeliveryMode(models.TextChoices):
        TEST = "test", "Teste seguro"
        LIVE = "live", "Produção"
        CONSOLE = "console", "Terminal / desenvolvimento"
        INTERNAL = "internal", "Interno"

    client = models.ForeignKey("clients.Client", on_delete=models.PROTECT, related_name="notifications", verbose_name="Cliente")
    service = models.ForeignKey(
        "services.Service", on_delete=models.SET_NULL, null=True, blank=True, related_name="notifications", verbose_name="Serviço"
    )
    renewal = models.ForeignKey(
        "billing.Renewal", on_delete=models.SET_NULL, null=True, blank=True, related_name="notifications", verbose_name="Renovação"
    )
    template = models.ForeignKey(
        NotificationTemplate, on_delete=models.SET_NULL, null=True, blank=True, related_name="logs", verbose_name="Modelo"
    )
    channel = models.CharField("Canal", max_length=20, choices=Channel.choices, default=Channel.EMAIL)
    recipient = models.CharField("Destinatário", max_length=250)
    original_recipient = models.CharField(
        "Destinatário original", max_length=250,
        blank=True,
        help_text="Preserva o destinatário real quando o modo de testes redireciona o envio.",
    )
    cc_recipients = models.TextField("CC", blank=True, help_text="Emails separados por vírgula.")
    reply_to = models.EmailField("Responder para", blank=True)
    subject = models.CharField("Assunto", max_length=250, blank=True)
    body = models.TextField("Mensagem")
    html_body = models.TextField("Mensagem HTML", blank=True)
    status = models.CharField("Estado", max_length=20, choices=Status.choices, default=Status.DRAFT, db_index=True)
    delivery_mode = models.CharField("Modo de envio", max_length=20, choices=DeliveryMode.choices, blank=True, db_index=True)
    is_automatic = models.BooleanField("Criada automaticamente", default=False, db_index=True)
    deduplication_key = models.CharField(
        "Chave de duplicação",
        max_length=180,
        blank=True,
        unique=True,
        null=True,
        help_text="Impede a criação repetida da mesma comunicação automática.",
    )
    scheduled_for = models.DateTimeField("Agendado para", null=True, blank=True, db_index=True)
    sent_at = models.DateTimeField("Enviado em", null=True, blank=True)
    sent_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="sent_notifications",
        verbose_name="Enviado por",
    )
    attempts_count = models.PositiveSmallIntegerField("Tentativas", default=0)
    max_attempts = models.PositiveSmallIntegerField("Máximo de tentativas", default=3, validators=[MinValueValidator(1)])
    last_attempt_at = models.DateTimeField("Última tentativa", null=True, blank=True)
    next_retry_at = models.DateTimeField("Próxima tentativa", null=True, blank=True, db_index=True)
    message_id = models.CharField("ID da mensagem", max_length=255, blank=True)
    error_message = models.TextField("Erro", blank=True)

    class Meta:
        verbose_name = "Notificação"
        verbose_name_plural = "Notificações"
        ordering = ["-created_at"]
        indexes = [
            models.Index(fields=["status", "scheduled_for"]),
            models.Index(fields=["status", "next_retry_at"]),
            models.Index(fields=["is_automatic", "created_at"]),
        ]

    def __str__(self):
        return f"{self.client} — {self.get_channel_display()}"

    @property
    def can_retry(self):
        return self.status == self.Status.FAILED and self.attempts_count < self.max_attempts

    def cc_list(self):
        return [item.strip() for item in self.cc_recipients.split(",") if item.strip()]


class NotificationAttempt(models.Model):
    class Result(models.TextChoices):
        SUCCESS = "success", "Sucesso"
        FAILED = "failed", "Falhou"
        SUPPRESSED = "suppressed", "Bloqueado"
        SKIPPED = "skipped", "Ignorado"

    notification = models.ForeignKey(
        NotificationLog,
        on_delete=models.CASCADE,
        related_name="attempts",
        verbose_name="Notificação",
    )
    attempted_at = models.DateTimeField("Tentativa em", auto_now_add=True, db_index=True)
    result = models.CharField("Resultado", max_length=20, choices=Result.choices, db_index=True)
    recipient_used = models.EmailField("Destinatário usado", blank=True)
    backend = models.CharField("Backend", max_length=255, blank=True)
    duration_ms = models.PositiveIntegerField("Duração (ms)", default=0)
    message_id = models.CharField("ID da mensagem", max_length=255, blank=True)
    error_message = models.TextField("Erro", blank=True)
    triggered_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="notification_attempts",
        verbose_name="Iniciada por",
    )

    class Meta:
        verbose_name = "Tentativa de envio"
        verbose_name_plural = "Tentativas de envio"
        ordering = ["-attempted_at"]

    def __str__(self):
        return f"{self.notification_id} — {self.get_result_display()}"
