# from django.contrib.auth.models import User
from django.conf import settings
from django.db import models
from django.utils import timezone


class EDSCertificate(models.Model):
    """
    Digital signature certificate model.

    Stores public X.509 certificates for users to validate their digital signatures.
    Only public keys/certificates are stored - NO private keys.
    """

    user = models.OneToOneField(
        # User, on_delete=models.CASCADE, related_name="eds_certificate"
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="eds_certificate",
    )

    # Certificate metadata
    subject = models.CharField(max_length=255, help_text="Certificate subject DN")
    issuer = models.CharField(max_length=255, help_text="Certificate issuer DN")
    serial_number = models.CharField(
        max_length=255, unique=True, help_text="Certificate serial number"
    )

    # Validity period
    valid_from = models.DateTimeField(help_text="Certificate validity start")
    valid_to = models.DateTimeField(help_text="Certificate validity end")

    # Public key/certificate in PEM format
    public_key_pem = models.TextField(
        help_text="X.509 certificate in PEM format (public key only)"
    )

    # Thumbprint (SHA256 hash of certificate)
    thumbprint = models.CharField(
        max_length=64,
        unique=True,
        help_text="SHA256 thumbprint of certificate (hex-encoded)",
    )

    # Status tracking
    is_revoked = models.BooleanField(
        default=False, help_text="Certificate revocation status"
    )
    revoked_at = models.DateTimeField(null=True, blank=True)

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        verbose_name = "EDS Certificate"
        verbose_name_plural = "EDS Certificates"

    def __str__(self) -> str:
        return f"{self.subject} ({self.serial_number})"

    def is_valid(self) -> bool:
        """Check if certificate is currently valid."""
        now = timezone.now()
        return self.valid_from <= now <= self.valid_to and not self.is_revoked


class AuthenticationNonce(models.Model):
    """
    Single-use nonce for signature-based authentication.

    Prevents replay attacks. Each authentication attempt requires:
    1. Server generates nonce
    2. Client signs nonce with their private key
    3. Server verifies signature and invalidates nonce
    """

    # user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="auth_nonces")
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="auth_nonces"
    )

    # Nonce value (random string)
    nonce = models.CharField(max_length=128, unique=True, db_index=True)

    # Status
    is_used = models.BooleanField(default=False)
    expires_at = models.DateTimeField(db_index=True)
    used_at = models.DateTimeField(null=True, blank=True)

    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name = "Authentication Nonce"
        verbose_name_plural = "Authentication Nonces"
        indexes = [
            models.Index(fields=["nonce", "is_used"]),
            models.Index(fields=["expires_at"]),
        ]

    def __str__(self) -> str:
        return f"Nonce for {self.user} (used: {self.is_used})"

    def is_valid(self) -> bool:
        """Check if nonce is still valid for authentication."""
        now = timezone.now()
        return not self.is_used and self.expires_at > now

    def mark_as_used(self) -> None:
        """Mark nonce as used (invalidate for future attempts)."""
        self.is_used = True
        self.used_at = timezone.now()
        self.save()


class SignatureVerificationLog(models.Model):
    """
    Audit log for signature verification attempts.

    Tracks all verification events for security monitoring and debugging.
    """

    VERIFICATION_STATUS_CHOICES = [
        ("success", "Successful verification"),
        ("failed_signature", "Signature verification failed"),
        ("failed_nonce", "Nonce validation failed"),
        ("failed_cert", "Certificate validation failed"),
        ("failed_revoked", "Certificate revoked"),
        ("failed_expired", "Certificate expired"),
        ("failed_invalid_format", "Invalid signature format"),
        ("error", "Verification error"),
    ]

    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="signature_logs",
        null=True,
        blank=True,
    )

    certificate = models.ForeignKey(
        EDSCertificate,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="verification_logs",
    )

    status = models.CharField(max_length=25, choices=VERIFICATION_STATUS_CHOICES)
    message = models.TextField(
        blank=True, help_text="Details about verification result"
    )

    ip_address = models.GenericIPAddressField(null=True, blank=True)
    user_agent = models.TextField(blank=True)

    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name = "Signature Verification Log"
        verbose_name_plural = "Signature Verification Logs"
        indexes = [
            models.Index(fields=["status", "-created_at"]),
            models.Index(fields=["user", "-created_at"]),
        ]

    def __str__(self) -> str:
        user_str = self.user.username if self.user else "Anonymous"
        return f"{user_str} - {self.get_status_display()}"


class SecurityLog(models.Model):
    """
    Unified audit trail for authentication and security events.

    Stores only non-sensitive metadata required for security monitoring.
    """

    EVENT_TYPE_CHOICES = [
        ("auth_success", "Successful authentication"),
        ("invalid_login", "Invalid login"),
        ("invalid_password", "Invalid password"),
        ("invalid_pem_key", "Invalid PEM key"),
        ("invalid_signature", "Invalid signature"),
        ("invalid_nonce", "Invalid nonce"),
        ("certificate_missing", "Certificate missing"),
        ("certificate_mismatch", "Certificate mismatch"),
        ("certificate_revoked", "Certificate revoked"),
        ("certificate_expired", "Certificate expired"),
        ("rate_limit_attempt", "Rate limit failed attempt"),
        ("rate_limit_locked", "Rate limit lockout"),
        ("rate_limit_blocked", "Rate limit blocked request"),
        ("backend_error", "Authentication backend error"),
    ]

    event_time = models.DateTimeField(auto_now_add=True, db_index=True)
    ip_address = models.GenericIPAddressField(null=True, blank=True, db_index=True)
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="security_logs",
    )
    event_type = models.CharField(
        max_length=50,
        choices=EVENT_TYPE_CHOICES,
        db_index=True,
    )
    details = models.JSONField(default=dict, blank=True)

    class Meta:
        verbose_name = "Security Log"
        verbose_name_plural = "Security Logs"
        ordering = ["-event_time"]
        indexes = [
            models.Index(fields=["event_type", "-event_time"]),
            models.Index(fields=["ip_address", "-event_time"]),
            models.Index(fields=["user", "-event_time"]),
        ]

    def __str__(self) -> str:
        user_repr = self.user.username if self.user else "Anonymous"
        return f"{self.event_time:%Y-%m-%d %H:%M:%S} | {self.event_type} | {user_repr}"


class FailedAuthenticationAttempt(models.Model):
    """
    Log for tracking failed authentication attempts for rate limiting.

    Used for monitoring and analyzing brute force attempts.
    Records both username-based and IP-based attempts.
    """

    ATTEMPT_TYPE_CHOICES = [
        ("eds_signature", "EDS Signature Authentication"),
        ("user_not_found", "User Not Found"),
        ("certificate_mismatch", "Certificate Mismatch"),
        ("certificate_missing", "Certificate Missing"),
        ("invalid_pem_key", "Invalid PEM Key"),
        ("invalid_nonce", "Invalid Nonce"),
        ("certificate_revoked", "Certificate Revoked"),
        ("certificate_expired", "Certificate Expired"),
        ("signature_invalid", "Signature Invalid"),
        ("rate_limit_locked", "Rate Limit Locked"),
    ]

    # Identifier information
    username = models.CharField(max_length=150, db_index=True)
    ip_address = models.GenericIPAddressField(db_index=True)

    # Attempt details
    attempt_type = models.CharField(max_length=50, choices=ATTEMPT_TYPE_CHOICES)
    reason = models.TextField(blank=True)

    # Rate limit status at time of attempt
    attempt_number = models.IntegerField(
        default=1, help_text="Which attempt in current cycle"
    )
    is_locked = models.BooleanField(
        default=False, help_text="Was account locked when attempt made"
    )

    # Additional context
    user_agent = models.TextField(blank=True)
    certificate_serial = models.CharField(max_length=255, blank=True)

    timestamp = models.DateTimeField(auto_now_add=True, db_index=True)

    class Meta:
        verbose_name = "Failed Authentication Attempt"
        verbose_name_plural = "Failed Authentication Attempts"
        ordering = ["-timestamp"]
        indexes = [
            models.Index(fields=["username", "-timestamp"]),
            models.Index(fields=["ip_address", "-timestamp"]),
            models.Index(fields=["is_locked", "-timestamp"]),
        ]

    def __str__(self) -> str:
        return (
            f"{self.username} from {self.ip_address} - {self.attempt_type} "
            f"(attempt #{self.attempt_number})"
        )
