/*
  Exemple pédagogique : vérification serveur d'un code confidentiel.

  Ce fichier accompagne le clavier numérique aléatoire côté navigateur.
  Il montre surtout une idée essentielle : la décision doit être prise côté serveur.

  Limites volontaires de l'exemple :
  - le code attendu est écrit en clair dans ce fichier ;
  - les tentatives sont suivies en session, donc de manière simplifiée ;
  - aucune base de données, aucun compte utilisateur, aucune vraie authentification forte
    ne sont mis en place ici.

  Ce fichier sert à comprendre le processus. Il ne doit pas être utilisé tel quel
  pour protéger un accès réel.
*/

session_start();

header('Content-Type: application/json; charset=utf-8');

// Code attendu pour la démonstration.
// Dans un vrai projet, il ne serait pas stocké ainsi en clair dans un fichier.
$expectedPin = '1234';

// Paramètres simples de contrôle.
// Ils servent ici à montrer les principes de limitation et de temporisation.
$maxAttempts = 3;
$delayBetweenAttempts = 5; // secondes entre deux tentatives
$lockDuration = 60;        // secondes de blocage après trop d'échecs

/*
  Initialisation des informations conservées en session.

  La session permet de garder un état entre plusieurs requêtes HTTP :
  nombre d'essais, date de la dernière tentative, éventuel blocage temporaire.

  Dans une application réelle, ces informations seraient souvent reliées à un compte,
  une adresse IP, un appareil, ou à d'autres signaux de sécurité.
*/
if (!isset($_SESSION['pin_attempts'])) {
    $_SESSION['pin_attempts'] = 0;
}

if (!isset($_SESSION['last_pin_attempt'])) {
    $_SESSION['last_pin_attempt'] = 0;
}

if (!isset($_SESSION['pin_locked_until'])) {
    $_SESSION['pin_locked_until'] = 0;
}

$now = time();

// Si un blocage est en cours, on refuse immédiatement la tentative.
if ($_SESSION['pin_locked_until'] > $now) {
    echo json_encode([
        'success' => false,
        'status'  => 'blocked',
        'message' => 'Trop de tentatives. Accès temporairement bloqué.',
        'remaining_seconds' => $_SESSION['pin_locked_until'] - $now,
        'attempts' => $_SESSION['pin_attempts']
    ]);
    exit;
}

// Si le blocage est terminé, on remet les compteurs à zéro.
if ($_SESSION['pin_locked_until'] > 0 && $_SESSION['pin_locked_until'] <= $now) {
    $_SESSION['pin_locked_until'] = 0;
    $_SESSION['pin_attempts'] = 0;
    $_SESSION['last_pin_attempt'] = 0;
}

/*
  Temporisation entre deux tentatives.

  Cette étape évite d'enchaîner les essais trop rapidement.
  Elle ne suffit pas à elle seule, mais elle montre que la sécurité se joue aussi
  dans le rythme imposé aux tentatives.
*/
$elapsed = $now - $_SESSION['last_pin_attempt'];

if ($_SESSION['last_pin_attempt'] > 0 && $elapsed < $delayBetweenAttempts) {
    echo json_encode([
        'success' => false,
        'status'  => 'wait',
        'message' => 'Veuillez patienter avant une nouvelle tentative.',
        'remaining_seconds' => $delayBetweenAttempts - $elapsed,
        'attempts' => $_SESSION['pin_attempts']
    ]);
    exit;
}

// Lecture du corps JSON envoyé par fetch() depuis app.js.
$rawInput = file_get_contents('php://input');
$data = json_decode($rawInput, true);

// Vérification du format JSON.
// Le serveur ne doit jamais supposer que le client envoie des données propres.
if (!is_array($data)) {
    echo json_encode([
        'success' => false,
        'status'  => 'error',
        'message' => 'Données invalides.'
    ]);
    exit;
}

// Vérification de la présence du code.
if (!isset($data['pin'])) {
    echo json_encode([
        'success' => false,
        'status'  => 'error',
        'message' => 'Aucun code reçu.'
    ]);
    exit;
}

$pin = (string) $data['pin'];

/*
  Vérification minimale du format attendu.

  Ici, nous acceptons exactement 4 chiffres.
  Cette validation est indispensable même si l'interface semble empêcher d'autres valeurs,
  car une requête peut être fabriquée sans passer par l'interface.
*/
if (!preg_match('/^\d{4}$/', $pin)) {
    echo json_encode([
        'success' => false,
        'status'  => 'error',
        'message' => 'Format de code invalide.'
    ]);
    exit;
}

// À partir de ce point, on considère qu'une vraie tentative a été faite.
$_SESSION['last_pin_attempt'] = $now;

/*
  Vérification du code.

  hash_equals() est utilisé ici pour garder une bonne habitude de comparaison
  entre chaînes sensibles. Cela ne transforme pas l'exemple en système complet,
  mais cela évite une comparaison trop naïve.
*/
if (hash_equals($expectedPin, $pin)) {
    $_SESSION['pin_attempts'] = 0;
    $_SESSION['last_pin_attempt'] = 0;
    $_SESSION['pin_locked_until'] = 0;

    echo json_encode([
        'success' => true,
        'status'  => 'accepted',
        // En production, on évite de renvoyer le code reçu dans le message.
        'message' => 'Code accepté.'
    ]);
    exit;
}

// Échec : on incrémente le compteur de tentatives.
$_SESSION['pin_attempts']++;

// Si le maximum est atteint, on active un blocage temporaire.
if ($_SESSION['pin_attempts'] >= $maxAttempts) {
    $_SESSION['pin_locked_until'] = $now + $lockDuration;

    echo json_encode([
        'success' => false,
        'status'  => 'blocked',
        'message' => 'Trop de tentatives. Accès temporairement bloqué.',
        'remaining_seconds' => $lockDuration,
        'attempts' => $_SESSION['pin_attempts']
    ]);
    exit;
}

// Sinon, on renvoie simplement le refus.
echo json_encode([
    'success' => false,
    'status'  => 'refused',
    // Message volontairement générique : on ne renvoie pas le code reçu.
    'message' => 'Code refusé.',
    'attempts' => $_SESSION['pin_attempts'],
    'remaining_attempts' => max(0, $maxAttempts - $_SESSION['pin_attempts'])
]);