from __future__ import annotations

import secrets
import string

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

from .models import CustomUser, LoginOTP


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


def issue_login_otp(user: CustomUser) -> LoginOTP:
    raw_code = generate_otp_code()
    expires_at = timezone.now() + timezone.timedelta(minutes=settings.OTP_EXPIRY_MINUTES)
    otp_record = LoginOTP.create_for_user(user=user, raw_code=raw_code, expires_at=expires_at)
    otp_record.raw_code = raw_code  # transient property used only for outbound email
    return otp_record


def send_login_otp_email(user: CustomUser, otp_code: str, expires_minutes: int) -> None:
    subject = "Your CRM login verification code"
    message = (
        f"Hi {user.first_name or user.username},\n\n"
        f"Your one-time login code is: {otp_code}\n"
        f"This code expires in {expires_minutes} minutes.\n\n"
        "If you did not request this login, please reset your password immediately."
    )
    send_mail(
        subject=subject,
        message=message,
        from_email=settings.DEFAULT_FROM_EMAIL,
        recipient_list=[user.email],
        fail_silently=False,
    )


def latest_active_otp(user: CustomUser) -> LoginOTP | None:
    now = timezone.now()
    return (
        LoginOTP.objects.filter(user=user, is_used=False, expires_at__gt=now)
        .order_by("-created_at")
        .first()
    )


def set_session_expiry(request, remember_me: bool) -> None:
    if remember_me:
        request.session.set_expiry(settings.REMEMBER_ME_AGE_SECONDS)
    else:
        request.session.set_expiry(0)


def clear_pending_otp_session(request) -> None:
    for key in ["pending_otp_user_id", "pending_otp_remember", "pending_otp_last_sent"]:
        request.session.pop(key, None)
