<?php
/**
 * LoginThrottle — limitation de débit anti-brute-force sur l'authentification.
 *
 * Compte les échecs récents par adresse IP (fenêtre glissante) et bloque au-delà
 * d'un seuil. Table SQLite `login_attempts` créée à la volée (idempotent).
 * Utilise exclusivement les helpers de Database (SQLite3 natif, pas de PDO).
 */
class LoginThrottle
{
    private const WINDOW_SECONDS = 900;   // fenêtre : 15 minutes
    private const MAX_FAILURES   = 10;    // échecs max par IP dans la fenêtre
    private const PURGE_AFTER    = '-1 day';

    private static function db(): Database
    {
        return Database::getInstance();
    }

    private static function ensureTable(): void
    {
        self::db()->execute(
            "CREATE TABLE IF NOT EXISTS login_attempts (
                id         INTEGER PRIMARY KEY AUTOINCREMENT,
                ip         TEXT NOT NULL,
                username   TEXT,
                success    INTEGER NOT NULL DEFAULT 0,
                created_at TEXT NOT NULL DEFAULT (datetime('now'))
            )"
        );
    }

    /** IP client (REMOTE_ADDR — on ne fait pas confiance aux en-têtes proxy). */
    public static function clientIp(): string
    {
        return (string)($_SERVER['REMOTE_ADDR'] ?? '0.0.0.0');
    }

    /** Vrai si l'IP a dépassé le seuil d'échecs dans la fenêtre. */
    public static function tooManyFailures(string $ip): bool
    {
        self::ensureTable();
        $n = (int)self::db()->fetchScalar(
            "SELECT COUNT(*) FROM login_attempts
             WHERE ip = ? AND success = 0
               AND created_at >= datetime('now', ?)",
            [$ip, '-' . self::WINDOW_SECONDS . ' seconds']
        );
        return $n >= self::MAX_FAILURES;
    }

    /** Enregistre une tentative (et purge best-effort les anciennes). */
    public static function record(string $ip, string $username, bool $success): void
    {
        self::ensureTable();
        self::db()->execute(
            "INSERT INTO login_attempts (ip, username, success) VALUES (?, ?, ?)",
            [$ip, $username, $success ? 1 : 0]
        );
        self::db()->execute(
            "DELETE FROM login_attempts WHERE created_at < datetime('now', ?)",
            [self::PURGE_AFTER]
        );
    }

    /** Réinitialise les échecs d'une IP (après une connexion réussie). */
    public static function clear(string $ip): void
    {
        self::ensureTable();
        self::db()->execute("DELETE FROM login_attempts WHERE ip = ? AND success = 0", [$ip]);
    }
}
