import secrets
from django.db import transaction
from django.contrib.auth.hashers import make_password, check_password

from apps.core.models import RecoveryCode


RECOVERY_CODE_COUNT = 10
RECOVERY_CODE_LENGTH = 10


def generate_recovery_codes(user):
    """
    Generate and store recovery codes.
    Returns the plain-text codes (shown once to the user).
    """
    codes = []

    for _ in range(RECOVERY_CODE_COUNT):
        code = secrets.token_hex(RECOVERY_CODE_LENGTH // 2).upper()
        codes.append(code)

        RecoveryCode.objects.create(
            user=user,
            code_hash=make_password(code)
        )

    return codes


def verify_recovery_code(user, code: str) -> bool:
    """
    Verify and consume a recovery code.
    """
    unused_codes = user.recovery_codes.filter(used=False)

    for recovery in unused_codes:
        if check_password(code, recovery.code_hash):
            recovery.used = True
            recovery.save(update_fields=["used"])
            return True

    return False

def regenerate_recovery_codes(user):
    """
    Delete old recovery codes and generate new ones.
    """
    with transaction.atomic():
        RecoveryCode.objects.filter(user=user).delete()
        return generate_recovery_codes(user)
