"""Small security helpers shared by the user-facing and admin login flows.

Keeps a lightweight in-memory brute-force throttle (keyed per client, e.g.
IP + username) and a constant-time comparison helper. This is intentionally
simple — fine for a single small-hosting Flask process. If the app is ever
run behind multiple worker processes, swap the in-memory dicts for a shared
store (e.g. Redis) so the lockout counters are seen by every worker.
"""
from __future__ import annotations

import hmac
import threading
import time

MAX_ATTEMPTS = 6           # failed attempts allowed…
WINDOW_SECONDS = 10 * 60   # …within this rolling window…
LOCKOUT_SECONDS = 15 * 60  # …before the key is locked out for this long.

_lock = threading.Lock()
_failures: dict[str, list[float]] = {}
_locked_until: dict[str, float] = {}


def _now() -> float:
    return time.time()


def is_locked(key: str) -> int:
    """Returns remaining lockout seconds for `key` (0 if not locked)."""
    with _lock:
        until = _locked_until.get(key)
        if until and until > _now():
            return int(until - _now())
        if until:
            _locked_until.pop(key, None)
            _failures.pop(key, None)
        return 0


def register_failure(key: str) -> None:
    """Records a failed login attempt and locks the key out if it has
    exceeded MAX_ATTEMPTS within WINDOW_SECONDS."""
    with _lock:
        now = _now()
        attempts = [t for t in _failures.get(key, []) if now - t < WINDOW_SECONDS]
        attempts.append(now)
        _failures[key] = attempts
        if len(attempts) >= MAX_ATTEMPTS:
            _locked_until[key] = now + LOCKOUT_SECONDS


def register_success(key: str) -> None:
    """Clears any failure history for `key` after a successful login."""
    with _lock:
        _failures.pop(key, None)
        _locked_until.pop(key, None)


def safe_equal(a: str, b: str) -> bool:
    """Constant-time string comparison — avoids leaking match length via timing."""
    return hmac.compare_digest((a or "").encode("utf-8"), (b or "").encode("utf-8"))
