import uuid
from datetime import timedelta

from django.conf import settings
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import User
from django.core.mail import send_mail
from django.db import models
from django.template.loader import render_to_string
from django.utils import timezone
from django.utils.html import strip_tags


class MagicLinkToken(models.Model):
    """Single-use, time-limited token for passwordless email login."""
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    email = models.EmailField(db_index=True)
    token = models.UUIDField(default=uuid.uuid4, unique=True, db_index=True)
    created_at = models.DateTimeField(auto_now_add=True)
    used = models.BooleanField(default=False)

    class Meta:
        ordering = ['-created_at']

    def __str__(self):
        return f"MagicLink for {self.email} ({'used' if self.used else 'active'})"

    @property
    def is_expired(self):
        expiry_minutes = getattr(settings, 'MAGIC_LINK_EXPIRY_MINUTES', 15)
        return timezone.now() > self.created_at + timedelta(minutes=expiry_minutes)

    @property
    def is_valid(self):
        return not self.used and not self.is_expired


import logging

logger = logging.getLogger(__name__)


def send_magic_link(email, request):
    """Generate a magic link token and email it to the user."""
    # Invalidate any previous unused tokens for this email
    MagicLinkToken.objects.filter(email=email, used=False).update(used=True)

    token_obj = MagicLinkToken.objects.create(email=email)

    login_url = request.build_absolute_uri(
        f'/auth/login/verify/{token_obj.token}/'
    )

    subject = f'Your {getattr(settings, "PLATFORM_NAME", "FlashSale")} Login Link'

    html_message = render_to_string('auth/magic_link_email.html', {
        'login_url': login_url,
        'expiry_minutes': getattr(settings, 'MAGIC_LINK_EXPIRY_MINUTES', 15),
        'platform_name': getattr(settings, 'PLATFORM_NAME', 'FlashSale'),
    })
    plain_message = strip_tags(html_message)

    try:
        send_mail(
            subject=subject,
            message=plain_message,
            from_email=settings.DEFAULT_FROM_EMAIL,
            recipient_list=[email],
            html_message=html_message,
            fail_silently=False,
        )
        return token_obj
    except Exception as e:
        logger.error(f"Failed to send magic link email to {email}: {e}")
        return None


class EmailBackend(ModelBackend):
    """
    Custom authentication backend that allows login via email address.
    Falls through to default ModelBackend for username/password.
    """
    def authenticate(self, request, username=None, password=None, **kwargs):
        # If an email is passed directly (from magic link verify)
        email = kwargs.get('email')
        if email:
            try:
                user = User.objects.get(email=email)
                return user
            except User.DoesNotExist:
                return None

        # Allow login by email in the username field (traditional form)
        if username and '@' in username:
            try:
                user = User.objects.get(email=username)
                if user.check_password(password):
                    return user
            except User.DoesNotExist:
                return None

        # Fall through to default username/password
        return super().authenticate(request, username=username, password=password, **kwargs)
