<?php
/**
 * Login rate-limiting using the login_attempts table.
 *
 *   login_is_locked($pdo, $username, $ip)        => bool
 *   login_attempt_failed($pdo, $username, $ip)
 *   login_attempt_success($pdo, $username, $ip)
 */

function login_max_attempts(): int
{
    return max(3, (int) osce_env('LOGIN_MAX_ATTEMPTS', 5));
}

function login_lockout_minutes(): int
{
    return max(1, (int) osce_env('LOGIN_LOCKOUT_MINUTES', 15));
}

function login_is_locked(PDO $pdo, string $username, string $ip): bool
{
    $window = login_lockout_minutes();
    $max    = login_max_attempts();

    $stmt = $pdo->prepare("
        SELECT COUNT(*) AS c
        FROM login_attempts
        WHERE success = 0
          AND attempted_at > (NOW() - INTERVAL ? MINUTE)
          AND (username = ? OR ip_address = ?)
    ");
    $stmt->execute([$window, $username, $ip]);
    $n = (int) ($stmt->fetch()['c'] ?? 0);
    return $n >= $max;
}

function login_attempt_log(PDO $pdo, string $username, string $ip, bool $success): void
{
    try {
        $stmt = $pdo->prepare("
            INSERT INTO login_attempts (username, ip_address, success, attempted_at)
            VALUES (?, ?, ?, NOW())
        ");
        $stmt->execute([substr($username, 0, 100), substr($ip, 0, 45), $success ? 1 : 0]);
    } catch (Throwable $e) {
        error_log('login_attempt_log failed: ' . $e->getMessage());
    }
}

function login_attempt_failed(PDO $pdo, string $username, string $ip): void
{
    login_attempt_log($pdo, $username, $ip, false);
}

function login_attempt_success(PDO $pdo, string $username, string $ip): void
{
    login_attempt_log($pdo, $username, $ip, true);
    // Clear that user's failed attempts so a fresh streak starts.
    try {
        $stmt = $pdo->prepare("DELETE FROM login_attempts WHERE username = ? AND success = 0");
        $stmt->execute([$username]);
    } catch (Throwable $e) {
        error_log('login_attempt_success cleanup failed: ' . $e->getMessage());
    }
}
