from datetime import timedelta

from django.contrib.auth import get_user_model
from django.utils import timezone

MAX_FAILED_ATTEMPTS = 5
LOCKOUT_DURATION = timedelta(minutes=15)


class ManagerApprovalError(Exception):
    pass


def verify_manager_pin(*, username, pin):
    """Verify a manager's approval PIN for overriding a below-minimum-price sale.

    Deliberately gives the same generic error for an unknown username, a
    non-manager username, a locked-out account, and a wrong PIN, so a seller
    probing the endpoint can't tell which case they hit.
    """
    User = get_user_model()
    generic_error = 'Invalid manager username or PIN.'

    try:
        manager = User.objects.get(username=username, is_active=True)
    except User.DoesNotExist:
        raise ManagerApprovalError(generic_error)

    if not manager.has_perm_code('sales.approve_price_overrides') or not manager.has_approval_pin:
        raise ManagerApprovalError(generic_error)

    now = timezone.now()
    if manager.approval_pin_locked_until and manager.approval_pin_locked_until > now:
        raise ManagerApprovalError(
            'This manager account is temporarily locked after too many failed PIN attempts. Try again later.'
        )

    if not manager.check_approval_pin(pin):
        manager.approval_pin_failed_attempts += 1
        if manager.approval_pin_failed_attempts >= MAX_FAILED_ATTEMPTS:
            manager.approval_pin_locked_until = now + LOCKOUT_DURATION
            manager.approval_pin_failed_attempts = 0
        manager.save(update_fields=['approval_pin_failed_attempts', 'approval_pin_locked_until'])
        raise ManagerApprovalError(generic_error)

    if manager.approval_pin_failed_attempts or manager.approval_pin_locked_until:
        manager.approval_pin_failed_attempts = 0
        manager.approval_pin_locked_until = None
        manager.save(update_fields=['approval_pin_failed_attempts', 'approval_pin_locked_until'])

    return manager
