from django.conf import settings
from django.contrib.auth.hashers import check_password, make_password
from django.db import models
from django.utils import timezone


class UserProfile(models.Model):
    user = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="k4w_profile",
        verbose_name="Utilizador",
    )
    avatar = models.FileField("Fotografia", upload_to="avatars/%Y/%m/", blank=True)
    phone = models.CharField("Telefone", max_length=40, blank=True)
    job_title = models.CharField("Função", max_length=120, blank=True)
    two_factor_required = models.BooleanField(
        "Exigir autenticação de dois fatores",
        default=False,
        help_text="Quando ativo, este utilizador só entra depois de validar um código temporário.",
    )
    last_two_factor_at = models.DateTimeField("Última validação 2FA", null=True, blank=True)
    created_at = models.DateTimeField("Criado em", auto_now_add=True)
    updated_at = models.DateTimeField("Atualizado em", auto_now=True)

    class Meta:
        verbose_name = "Perfil de utilizador"
        verbose_name_plural = "Perfis de utilizadores"

    def __str__(self):
        return self.user.get_full_name() or self.user.get_username()


class RecoveryCode(models.Model):
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="k4w_recovery_codes",
        verbose_name="Utilizador",
    )
    code_hash = models.CharField("Código protegido", max_length=255)
    created_at = models.DateTimeField("Criado em", auto_now_add=True)
    used_at = models.DateTimeField("Utilizado em", null=True, blank=True)

    class Meta:
        verbose_name = "Código de recuperação"
        verbose_name_plural = "Códigos de recuperação"
        ordering = ["used_at", "created_at"]

    @classmethod
    def create_for_user(cls, user, raw_code):
        return cls.objects.create(user=user, code_hash=make_password(raw_code))

    def matches(self, raw_code):
        return self.used_at is None and check_password(raw_code, self.code_hash)

    def consume(self):
        self.used_at = timezone.now()
        self.save(update_fields=["used_at"])

    def __str__(self):
        state = "utilizado" if self.used_at else "disponível"
        return f"{self.user} — {state}"


class SecurityEvent(models.Model):
    class EventType(models.TextChoices):
        LOGIN_SUCCESS = "login_success", "Login efetuado"
        LOGIN_FAILED = "login_failed", "Login falhado"
        OTP_SUCCESS = "otp_success", "Segundo fator validado"
        OTP_FAILED = "otp_failed", "Segundo fator inválido"
        OTP_ENABLED = "otp_enabled", "2FA ativado"
        OTP_DISABLED = "otp_disabled", "2FA desativado"
        RECOVERY_USED = "recovery_used", "Código de recuperação utilizado"
        RECOVERY_REGENERATED = "recovery_regenerated", "Códigos de recuperação regenerados"
        PROFILE_UPDATED = "profile_updated", "Perfil atualizado"
        PASSWORD_RESET_REQUESTED = "password_reset_requested", "Recuperação de palavra-passe pedida"
        PASSWORD_RESET_COMPLETED = "password_reset_completed", "Palavra-passe recuperada"

    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="k4w_security_events",
        verbose_name="Utilizador",
    )
    event_type = models.CharField("Evento", max_length=40, choices=EventType.choices, db_index=True)
    username_entered = models.CharField("Identificador introduzido", max_length=254, blank=True)
    ip_address = models.GenericIPAddressField("Endereço IP", null=True, blank=True)
    user_agent = models.CharField("Navegador", max_length=500, blank=True)
    details = models.JSONField("Detalhes", default=dict, blank=True)
    created_at = models.DateTimeField("Data", auto_now_add=True, db_index=True)

    class Meta:
        verbose_name = "Evento de segurança"
        verbose_name_plural = "Eventos de segurança"
        ordering = ["-created_at"]

    def __str__(self):
        return f"{self.get_event_type_display()} — {self.created_at:%d/%m/%Y %H:%M}"
