import secrets
from datetime import timedelta

from django.core.mail import send_mail
from django.conf import settings
from django.utils import timezone

from apps.accounts.models import OneTimePassword


def generate_temp_password(length: int = 10) -> str:
    alphabet = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789"
    return "".join(secrets.choice(alphabet) for _ in range(length))


def send_investor_credentials(email: str, password: str, name: str = "") -> None:
    portal = f"{settings.FRONTEND_URL.rstrip('/')}/investors#login"
    greeting = f"Hello {name}," if name else "Hello,"
    send_mail(
        subject="Your Shopno Holdings investor login",
        message=(
            f"{greeting}\n\n"
            "Your investor application has been approved.\n\n"
            f"Portal: {portal}\n"
            f"Email: {email}\n"
            f"Password: {password}\n\n"
            "Sign in and change this password after first login.\n\n"
            "Shopno Holdings Limited"
        ),
        from_email=settings.DEFAULT_FROM_EMAIL,
        recipient_list=[email],
        fail_silently=False,
    )


def generate_otp_code(length: int = 6) -> str:
    return "".join(secrets.choice("0123456789") for _ in range(length))


def issue_otp(user, purpose: str, ttl_minutes: int = 10) -> OneTimePassword:
    OneTimePassword.objects.filter(user=user, purpose=purpose, consumed_at__isnull=True).update(
        consumed_at=timezone.now()
    )
    otp = OneTimePassword.objects.create(
        user=user,
        purpose=purpose,
        code=generate_otp_code(),
        expires_at=timezone.now() + timedelta(minutes=ttl_minutes),
    )
    send_mail(
        subject=f"Shopno Holdings verification code ({purpose})",
        message=f"Your Shopno Holdings code is {otp.code}. It expires in {ttl_minutes} minutes.",
        from_email=settings.DEFAULT_FROM_EMAIL,
        recipient_list=[user.email],
        fail_silently=True,
    )
    return otp


def verify_otp(user, purpose: str, code: str) -> OneTimePassword | None:
    otp = (
        OneTimePassword.objects.filter(user=user, purpose=purpose, consumed_at__isnull=True)
        .order_by("-created_at")
        .first()
    )
    if otp is None:
        return None
    otp.attempt_count += 1
    if not otp.is_valid or otp.code != code.strip():
        otp.save(update_fields=["attempt_count"])
        return None
    otp.consumed_at = timezone.now()
    otp.save(update_fields=["consumed_at", "attempt_count"])
    return otp
