<?php
use PHPUnit\Framework\TestCase;
require_once __DIR__ . '/../src/db.php';
require_once __DIR__ . '/../src/auth.php';
final class AuthTest extends TestCase {
    public function testVerifierIdentifiants(): void {
        $pdo = db_test();
        creer_admin($pdo, 'direction', 'S3cret!isit');
        $this->assertTrue(verifier_identifiants($pdo, 'direction', 'S3cret!isit'));
        $this->assertFalse(verifier_identifiants($pdo, 'direction', 'mauvais'));
        $this->assertFalse(verifier_identifiants($pdo, 'inconnu', 'S3cret!isit'));
    }
    public function testHashJamaisEnClair(): void {
        $pdo = db_test();
        creer_admin($pdo, 'a', 'motdepasse');
        $h = $pdo->query('SELECT pass_hash FROM admins')->fetchColumn();
        $this->assertStringNotContainsString('motdepasse', $h);
    }
    // Revue Task 9 — verrou anti-force-brute sur la connexion admin (miroir d'AntispamTest)
    public function testConnexionBloqueeApresCinqTentatives(): void {
        $pdo = db_test();
        for ($i = 0; $i < 3; $i++) journaliser_connexion($pdo, '10.0.0.1', false);
        $this->assertFalse(connexion_bloquee($pdo, '10.0.0.1')); // 3 < 5 : encore libre
        journaliser_connexion($pdo, '10.0.0.1', false);
        $this->assertFalse(connexion_bloquee($pdo, '10.0.0.1')); // 4 < 5 : encore libre
        journaliser_connexion($pdo, '10.0.0.1', false);
        $this->assertTrue(connexion_bloquee($pdo, '10.0.0.1'));  // 5e tentative : bloqué
        $this->assertFalse(connexion_bloquee($pdo, '10.0.0.2')); // autre IP : libre
    }
    public function testConnexionSuccesAussiJournalise(): void {
        $pdo = db_test();
        journaliser_connexion($pdo, '10.0.0.3', true);
        journaliser_connexion($pdo, '10.0.0.3', false);
        $oks = $pdo->query('SELECT ok FROM connexions_log ORDER BY id')->fetchAll(PDO::FETCH_COLUMN);
        $this->assertSame([1, 0], array_map('intval', $oks));
    }
    public function testConnexionFenetreGlissanteExclutTentativesAnciennes(): void {
        $pdo = db_test();
        $pdo->exec("INSERT INTO connexions_log (ip, ok, created_at) VALUES ('x', 0, datetime('now','-2 hour'))");
        for ($i = 0; $i < 4; $i++) journaliser_connexion($pdo, 'x', false);
        $this->assertFalse(connexion_bloquee($pdo, 'x')); // 4 dans la fenêtre : la ligne de -2 h ne compte pas
        journaliser_connexion($pdo, 'x', false);
        $this->assertTrue(connexion_bloquee($pdo, 'x'));  // 5 dans la fenêtre
    }
    // Revue Task 9 — expiration de session admin (helper pur, testable sans session réelle)
    public function testSessionAdminValideFraicheEtBornes(): void {
        $t = 1_000_000_000;
        $this->assertTrue(session_admin_valide(['admin_depuis' => $t, 'admin_actif' => $t], $t)); // fraîche
        // Bornes inclusives : à exactement 8 h de session et 1 h d'inactivité, encore valide
        $this->assertTrue(session_admin_valide(['admin_depuis' => $t - 8 * 3600, 'admin_actif' => $t - 3600], $t));
    }
    public function testSessionAdminInvalideExpirations(): void {
        $t = 1_000_000_000;
        $this->assertFalse(session_admin_valide([], $t)); // jamais connecté
        $this->assertFalse(session_admin_valide(['admin_actif' => $t], $t)); // admin_depuis absent
        $this->assertFalse(session_admin_valide(['admin_depuis' => $t - 7200, 'admin_actif' => $t - 7200], $t)); // 2 h d'inactivité
        $this->assertFalse(session_admin_valide(['admin_depuis' => $t - 9 * 3600, 'admin_actif' => $t - 60], $t)); // 9 h absolues, même active
        $this->assertFalse(session_admin_valide(['admin_depuis' => $t - 8 * 3600 - 1, 'admin_actif' => $t], $t)); // juste au-delà de 8 h
        $this->assertFalse(session_admin_valide(['admin_depuis' => $t, 'admin_actif' => $t - 3601], $t)); // juste au-delà d'1 h
    }
    // Revue Task 9 — unicité du login insensible à la casse (aligne le schéma de test
    // SQLite sur le comportement MySQL utf8mb4_unicode_ci de la prod)
    public function testLoginAdminUniqueInsensibleALaCasse(): void {
        $pdo = db_test();
        creer_admin($pdo, 'Direction', 'motdepasse-long');
        $this->assertTrue(verifier_identifiants($pdo, 'DIRECTION', 'motdepasse-long')); // casse indifférente, comme en prod
        $this->expectException(PDOException::class);
        creer_admin($pdo, 'direction', 'autre-mot-de-passe');
    }
}
