<?php
// auth.php - API d'authentification avec JWT
require_once 'config.php';
require_once 'JwtManager.php';

class AuthService {
    
    private $pdo;
    
    public function __construct() {
        $this->pdo = DatabaseConfig::getConnection();
    }
    
    /**
     * Authentifier un utilisateur avec mot de passe hashé
     */
    public function login($nomUt, $motPasse) {
        try {
            $sql = "SELECT NUt, NomUt, NomPrenoms, LeGroupe, MotPasse, actif 
                    FROM user 
                    WHERE NomUt = :nomUt AND actif = 1";
            
            $stmt = $this->pdo->prepare($sql);
            $stmt->bindParam(':nomUt', $nomUt, PDO::PARAM_STR);
            $stmt->execute();
            
            $user = $stmt->fetch();
            
            // Vérifier le mot de passe hashé
            if ($user && password_verify($motPasse, $user['MotPasse'])) {
                // Payload pour le JWT
                $payload = [
                    'user_id' => $user['NUt'],
                    'username' => $user['NomUt'],
                    'nom_prenoms' => $user['NomPrenoms'],
                    'groupe' => $user['LeGroupe'],
                    'login_time' => time()
                ];
                
                // Générer les tokens JWT
                $accessToken = JwtManager::createToken($payload);
                $refreshToken = JwtManager::createRefreshToken($payload);
                
                // Enregistrer les informations de session
                $this->updateUserSession($user['NUt'], $accessToken);
                
                // Données utilisateur à retourner
                $userData = [
                    'id' => $user['NUt'],
                    'nom' => $user['NomUt'],
                    'prenoms' => $user['NomPrenoms'],
                    'groupe' => $user['LeGroupe'],
                    'token' => $accessToken,
                    'refresh_token' => $refreshToken,
                    'token_type' => 'Bearer',
                    'expires_in' => DatabaseConfig::getSecurityConfig()['session_timeout'],
                    'connexion_time' => date('Y-m-d H:i:s')
                ];
                
                // Log de connexion
                Utils::logError("Connexion JWT réussie pour l'utilisateur: " . $user['NomUt']);
                
                return $userData;
            }
            
            return false;
            
        } catch (PDOException $e) {
            Utils::logError("Erreur lors de l'authentification", ['error' => $e->getMessage()]);
            throw new Exception("Erreur lors de l'authentification");
        }
    }
    
    /**
     * Vérifier un token JWT
     */
    public function verifyToken($token) {
        try {
            // Vérifier si le token est en blacklist
            if (JwtManager::isTokenBlacklisted($token)) {
                throw new Exception('Token révoqué');
            }
            
            // Vérifier et décoder le JWT
            $payload = JwtManager::verifyToken($token);
            
            // Vérifier que l'utilisateur existe toujours et est actif
            $sql = "SELECT NUt, NomUt, NomPrenoms, LeGroupe 
                    FROM user 
                    WHERE NUt = :userId AND actif = 1";
            
            $stmt = $this->pdo->prepare($sql);
            $stmt->bindParam(':userId', $payload['user_id'], PDO::PARAM_INT);
            $stmt->execute();
            
            $user = $stmt->fetch();
            if (!$user) {
                throw new Exception('Utilisateur non trouvé ou inactif');
            }
            
            // Retourner les données utilisateur avec le payload JWT
            return array_merge($user, [
                'jwt_payload' => $payload,
                'token_valid' => true
            ]);
            
        } catch (Exception $e) {
            Utils::logError("Erreur lors de la vérification du token JWT", ['error' => $e->getMessage()]);
            return false;
        }
    }
    
    /**
     * Déconnexion - Invalider le token JWT
     */
    public function logout($token) {
        try {
            // Ajouter le token à la blacklist
            JwtManager::blacklistToken($token);
            
            // Mettre à jour la session utilisateur
            $payload = JwtManager::verifyToken($token);
            if ($payload && isset($payload['user_id'])) {
                $this->clearUserSession($payload['user_id']);
            }
            
            Utils::logError("Déconnexion JWT réussie");
            return true;
            
        } catch (Exception $e) {
            Utils::logError("Erreur lors de la déconnexion JWT", ['error' => $e->getMessage()]);
            return false;
        }
    }
    
    /**
     * Générer un token simple
     */
    private function generateToken($userId) {
        return hash('sha256', $userId . time() . rand(1000, 9999));
    }
    
    /**
     * Enregistrer les informations de session JWT
     */
    private function updateUserSession($userId, $token) {
        try {
            // Enregistrer l'horodatage de la dernière connexion
            $sql = "UPDATE user SET derniere_connexion = NOW(), token = NULL WHERE NUt = :userId";
            $stmt = $this->pdo->prepare($sql);
            $stmt->bindParam(':userId', $userId, PDO::PARAM_INT);
            $stmt->execute();
            
            // Note: Avec JWT, on ne stocke plus le token en base
            // Les informations sont dans le token lui-même
            
        } catch (PDOException $e) {
            Utils::logError("Erreur lors de la mise à jour de session", ['error' => $e->getMessage()]);
        }
    }
    
    /**
     * Nettoyer la session utilisateur
     */
    private function clearUserSession($userId) {
        try {
            $sql = "UPDATE user SET token = NULL WHERE NUt = :userId";
            $stmt = $this->pdo->prepare($sql);
            $stmt->bindParam(':userId', $userId, PDO::PARAM_INT);
            $stmt->execute();
            
        } catch (PDOException $e) {
            Utils::logError("Erreur lors du nettoyage de session", ['error' => $e->getMessage()]);
        }
    }
    
    /**
     * Obtenir tous les utilisateurs (pour admin)
     */
    public function getUsers() {
        try {
            $sql = "SELECT NUt, NomUt, NomPrenoms, LeGroupe, actif 
                    FROM user 
                    ORDER BY NomUt";
            
            $stmt = $this->pdo->prepare($sql);
            $stmt->execute();
            
            return $stmt->fetchAll();
            
        } catch (PDOException $e) {
            Utils::logError("Erreur lors de la récupération des utilisateurs", ['error' => $e->getMessage()]);
            throw new Exception("Erreur lors de la récupération des utilisateurs");
        }
    }
    
    /**
     * Créer un nouvel utilisateur avec mot de passe hashé
     */
    public function createUser($nomUt, $motPasse, $nomPrenoms, $groupe) {
        try {
            $hashedPassword = password_hash($motPasse, PASSWORD_DEFAULT);
            
            $sql = "INSERT INTO user (NomUt, MotPasse, NomPrenoms, LeGroupe, actif) 
                    VALUES (:nomUt, :motPasse, :nomPrenoms, :groupe, 1)";
            
            $stmt = $this->pdo->prepare($sql);
            $stmt->bindParam(':nomUt', $nomUt, PDO::PARAM_STR);
            $stmt->bindParam(':motPasse', $hashedPassword, PDO::PARAM_STR);
            $stmt->bindParam(':nomPrenoms', $nomPrenoms, PDO::PARAM_STR);
            $stmt->bindParam(':groupe', $groupe, PDO::PARAM_STR);
            
            return $stmt->execute();
            
        } catch (PDOException $e) {
            Utils::logError("Erreur lors de la création de l'utilisateur", ['error' => $e->getMessage()]);
            throw new Exception("Erreur lors de la création de l'utilisateur");
        }
    }
    
    /**
     * Mettre à jour le mot de passe d'un utilisateur
     */
    public function updatePassword($nomUt, $newPassword) {
        try {
            $hashedPassword = password_hash($newPassword, PASSWORD_DEFAULT);
            
            $sql = "UPDATE user SET MotPasse = :motPasse WHERE NomUt = :nomUt";
            $stmt = $this->pdo->prepare($sql);
            $stmt->bindParam(':motPasse', $hashedPassword, PDO::PARAM_STR);
            $stmt->bindParam(':nomUt', $nomUt, PDO::PARAM_STR);
            
            return $stmt->execute();
            
        } catch (PDOException $e) {
            Utils::logError("Erreur lors de la mise à jour du mot de passe", ['error' => $e->getMessage()]);
            throw new Exception("Erreur lors de la mise à jour du mot de passe");
        }
    }
}

// Traitement des requêtes
Utils::setCorsHeaders();

$authService = new AuthService();
$method = $_SERVER['REQUEST_METHOD'];

try {
    switch ($method) {
        case 'POST':
            $input = Utils::getJsonInput();
            
            if (isset($input['action'])) {
                switch ($input['action']) {
                    case 'login':
                        // Validation sécurisée des entrées
                        $validatedInput = Utils::validateInput($input, [
                            'username' => [
                                'required' => true,
                                'type' => 'string',
                                'min_length' => 3,
                                'max_length' => 50,
                                'pattern' => '/^[a-zA-Z0-9_-]+$/',
                                'message' => 'Nom d\'utilisateur invalide (3-50 caractères alphanumériques)'
                            ],
                            'password' => [
                                'required' => true,
                                'type' => 'string',
                                'min_length' => 4,
                                'max_length' => 255,
                                'message' => 'Mot de passe invalide'
                            ]
                        ]);
                        
                        $user = $authService->login($validatedInput['username'], $validatedInput['password']);
                        
                        if ($user) {
                            Utils::jsonResponse($user, true, 'Connexion réussie');
                        } else {
                            Utils::errorResponse('Nom d\'utilisateur ou mot de passe incorrect', 401);
                        }
                        break;
                        
                    case 'logout':
                        if (!isset($input['token'])) {
                            Utils::errorResponse('Token requis');
                        }
                        
                        $result = $authService->logout($input['token']);
                        
                        if ($result) {
                            Utils::jsonResponse([], true, 'Déconnexion réussie');
                        } else {
                            Utils::errorResponse('Erreur lors de la déconnexion');
                        }
                        break;
                        
                    case 'verify':
                        // Vérification via header Authorization (méthode recommandée)
                        $token = JwtManager::extractTokenFromHeader();
                        if (!$token) {
                            // Fallback: chercher dans le body
                            $token = $input['token'] ?? null;
                        }
                        
                        if (!$token) {
                            Utils::errorResponse('Token requis dans Authorization header ou body');
                        }
                        
                        $user = $authService->verifyToken($token);
                        
                        if ($user) {
                            Utils::jsonResponse($user, true, 'Token JWT valide');
                        } else {
                            Utils::errorResponse('Token JWT invalide', 401);
                        }
                        break;
                        
                    case 'refresh':
                        // Renouveler un token avec le refresh token
                        if (!isset($input['refresh_token'])) {
                            Utils::errorResponse('Refresh token requis');
                        }
                        
                        try {
                            $payload = JwtManager::verifyToken($input['refresh_token']);
                            
                            // Vérifier que c'est un refresh token
                            if (($payload['type'] ?? '') !== 'refresh') {
                                throw new Exception('Type de token invalide');
                            }
                            
                            // Générer un nouveau token d'accès
                            unset($payload['type'], $payload['exp'], $payload['iat'], $payload['jti']);
                            $newToken = JwtManager::createToken($payload);
                            
                            Utils::jsonResponse([
                                'token' => $newToken,
                                'token_type' => 'Bearer',
                                'expires_in' => DatabaseConfig::getSecurityConfig()['session_timeout']
                            ], true, 'Token renouvelé');
                            
                        } catch (Exception $e) {
                            Utils::errorResponse('Refresh token invalide: ' . $e->getMessage(), 401);
                        }
                        break;
                        
                    default:
                        Utils::errorResponse('Action non reconnue');
                }
            } else {
                Utils::errorResponse('Action non spécifiée');
            }
            break;
            
        case 'GET':
            // Vérifier le token pour les requêtes GET
            $headers = getallheaders();
            $token = isset($headers['Authorization']) ? str_replace('Bearer ', '', $headers['Authorization']) : null;
            
            if (!$token) {
                Utils::errorResponse('Token d\'authentification requis', 401);
            }
            
            $user = $authService->verifyToken($token);
            if (!$user) {
                Utils::errorResponse('Token invalide', 401);
            }
            
            // Si l'utilisateur est admin, il peut voir la liste des utilisateurs
            if ($user['LeGroupe'] === 'ADMINISTRATEUR') {
                $users = $authService->getUsers();
                Utils::jsonResponse($users, true, 'Liste des utilisateurs');
            } else {
                Utils::errorResponse('Accès non autorisé', 403);
            }
            break;
            
        default:
            Utils::errorResponse('Méthode non supportée', 405);
    }
    
} catch (Exception $e) {
    Utils::logError("Erreur dans auth.php", ['error' => $e->getMessage()]);
    Utils::errorResponse('Erreur interne du serveur', 500);
}
?>