<?php


require_once __DIR__ . '/../core/AbstractPdo.php';

class CandidatService extends AbstractPdo
{
    protected $table = 'candidat';
    protected $primaryKey = 'id';
    protected $inscriptionListPage =  '/est-concours/app/view/candidat/inscription/list/index.php';
    protected $inscriptionCreate =  '/est-concours/app/view/candidat/inscription/create/index.php';

    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Authenticate admin user with encrypted password
     */
    public function login($email, $password)
    {
        // Check if admin exists with this email
        $sql = "SELECT * FROM {$this->table} WHERE email = :email";
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute(['email' => $email]);
        $candidat = $stmt->fetch(PDO::FETCH_ASSOC);

        if (!$candidat) {
            return [
                'success' => false,
                'message' => 'Email ou mot de passe incorrect'
            ];
        }

        // Check if account is blocked
        if ($candidat['blocked'] == 1) {
            return [
                'success' => false,
                'message' => 'Votre compte est bloqué. Veuillez contacter l\'administrateur.'
            ];
        }

        // Verify password using password_verify()
        if (!password_verify($password, $candidat['password'])) {
            // Increment failed login attempts
            $this->incrementFailedAttempts($candidat['id']);

            // Check if should be blocked (3 failed attempts)
            $sql = "SELECT cnx_fail_number FROM {$this->table} WHERE id = :id";
            $stmt = $this->pdo->prepare($sql);
            $stmt->execute(['id' => $candidat['id']]);
            $failCount = $stmt->fetch(PDO::FETCH_ASSOC)['cnx_fail_number'];

            if ($failCount >= 3) {
                $this->blockCandidat($candidat['id']);
                return [
                    'success' => false,
                    'message' => 'Trop de tentatives échouées. Votre compte a été bloqué.'
                ];
            }

            return [
                'success' => false,
                'message' => 'Email ou mot de passe incorrect. Tentative ' . $failCount . '/3'
            ];
        }
        $this->resetFailedAttempts($candidat['id']);
        unset($candidat['password']);
        $_SESSION['candidat'] = $candidat ;
        return [
            'success' => true,
            'data' => $candidat,
            'message' => 'Login successful'
        ];
    }


    /**
     * Update admin password with encryption
     */
    public function updatePassword($candidatId, $newPassword)
    {
        $hashedPassword = password_hash($newPassword, PASSWORD_DEFAULT);

        $sql = "UPDATE candidat SET password = :password WHERE id = :id";
        $stmt = $this->pdo->prepare($sql);
        $result = $stmt->execute([
            'password' => $hashedPassword,
            'id' => $candidatId
        ]);

        if ($result) {
            return ['success' => true, 'message' => 'Mot de passe mis à jour avec succès'];
        }
        return ['success' => false, 'message' => 'Erreur lors de la mise à jour'];
    }

    /**
     * Reset admin password (admin initiated)
     */
    public function resetPassword($email, $newPassword)
    {
        // Verify email exists
        $sql = "SELECT id FROM {$this->table} WHERE email = :email";
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute(['email' => $email]);
        $candidat = $stmt->fetch(PDO::FETCH_ASSOC);

        if (!$candidat) {
            return ['success' => false, 'message' => 'Email non trouvé'];
        }

        return $this->updatePassword($candidat['id'], $newPassword);
    }

    /**
     * Check password strength
     */
    public function validatePasswordStrength($password)
    {
        $errors = [];

        if (strlen($password) < 8) {
            $errors[] = 'Le mot de passe doit contenir au moins 8 caractères';
        }
        if (!preg_match('/[A-Z]/', $password)) {
            $errors[] = 'Le mot de passe doit contenir au moins une majuscule';
        }
        if (!preg_match('/[a-z]/', $password)) {
            $errors[] = 'Le mot de passe doit contenir au moins une minuscule';
        }
        if (!preg_match('/[0-9]/', $password)) {
            $errors[] = 'Le mot de passe doit contenir au moins un chiffre';
        }
        if (!preg_match('/[!@#$%^&*(),.?":{}|<>]/', $password)) {
            $errors[] = 'Le mot de passe doit contenir au moins un caractère spécial';
        }

        return [
            'valid' => empty($errors),
            'errors' => $errors
        ];
    }


    /**
     * Increment failed login attempts
     */
    private function incrementFailedAttempts($candidatId)
    {
        $sql = "UPDATE {$this->table} SET cnx_fail_number = cnx_fail_number + 1 WHERE id = :id";
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute(['id' => $candidatId]);
    }

    /**
     * Reset failed login attempts
     */
    private function resetFailedAttempts($candidatId)
    {
        $sql = "UPDATE {$this->table} SET cnx_fail_number = 0 WHERE id = :id";
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute(['id' => $candidatId]);
    }

    /**
     * Block admin account
     */
    private function blockCandidat($candidatId)
    {
        $sql = "UPDATE {$this->table} SET blocked = 1 WHERE id = :id";
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute(['id' => $candidatId]);
    }

    /**
     * Unblock admin account
     */
    public function unblockCandidat($candidatId)
    {
        $sql = "UPDATE {$this->table} SET blocked = 0, cnx_fail_number = 0 WHERE id = :id";
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute(['id' => $candidatId]);
        return ['success' => true, 'message' => 'Compte débloqué avec succès'];
    }

    /**
     * Get admin by ID
     */
    public function getCandidatById($id)
    {
        $sql = "SELECT id, email, nom, prenom, cin, phone FROM {$this->table} WHERE id = :id";
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute(['id' => $id]);
        return $stmt->fetch(PDO::FETCH_ASSOC);
    }


    /**
     * Get candidats with search criteria
     */
    public function search($searchData, $page = 1, $perPage = 10)
    {
        $filters = [];
        $searchFields = ['nom', 'prenom', 'email', 'cin', 'phone'];

        foreach ($searchFields as $field) {
            if (!empty($searchData[$field])) {
                $filters[$field] = [
                    'value' => $searchData[$field],
                    'like' => true
                ];
            }
        }

        $offset = ($page - 1) * $perPage;
        $candidats = $this->findMultiple($filters, 'id DESC', $perPage, $offset);
        $total = $this->count($filters);

        return [
            'data' => $candidats,
            'total' => $total,
            'page' => $page,
            'perPage' => $perPage,
            'totalPages' => ceil($total / $perPage)
        ];
    }

    /**
     * Get candidat by ID
     */
    public function getCandidat($id)
    {
        return $this->findOne($id);
    }

    /**
     * Create a new candidat
     */
    public function createCandidat($data)
    {
        if (empty($data['password'])) {
            $data['password'] = password_hash("12345678", PASSWORD_DEFAULT);
        } else {
            $data['password'] = password_hash($data['password'], PASSWORD_DEFAULT);
        }
        return $this->insert($data);
    }

    /**
     * Update a candidat
     */
    public function updateCandidat($id, $data)
    {
        // CHANGEMENT PASSWORD
        if (!empty($data['new_password'])) {
            $sql = "SELECT password  FROM candidat WHERE id = :id";
            $stmt = $this->pdo->prepare($sql);
            $stmt->execute([
                'id' => $id
            ]);
            $candidat = $stmt->fetch(PDO::FETCH_ASSOC);
            if (!$candidat) {
                return [
                    'success' => false,
                    'message' => 'Etudiant introuvable'
                ];
            }
            // Vérifier ancien mot de passe
            if (!password_verify($data['current_password'], $candidat['password'])) {
                return [
                    'success' => false,
                    'message' => 'Mot de passe actuel incorrect'
                ];
            }
            // Vérifier confirmation
            if ($data['new_password'] !== $data['confirm_password']) {
                return [
                    'success' => false,
                    'message' => 'La confirmation du mot de passe est incorrecte'
                ];
            }
            // Vérifier sécurité password
            $check = $this->validatePasswordStrength($data['new_password']);


            if (!$check['valid']) {
                return [
                    'success' => false,
                    'message' => implode("\n", $check['errors'])
                ];
            }
            $hashed = password_hash($data['new_password'], PASSWORD_DEFAULT);
            $sql = "UPDATE candidat SET password=:password WHERE id=:id";
            $stmt = $this->pdo->prepare($sql);
            $stmt->execute([
                'password' => $hashed,
                'id' => $id
            ]);

        }
        unset($data['current_password']);
        unset($data['new_password']);
        unset($data['confirm_password']);
        if (!empty($data)) {
            $this->update($id, $data);
        }
        return [
            'success' => true,
            'message' => 'Etudiant modifié avec succès'
        ];
    }

    /**
     * Delete a candidat
     */
    public function deleteCandidat($id)
    {
        return $this->delete($id);
    }

    /**
     * Check candidat inscriptions and determine redirect URL
     */
    public function checkCandidatInscriptions($candidatId)
    {
        try {
            // Get count of inscriptions for this candidat
            $sql = "SELECT COUNT(*) as total FROM inscriptions WHERE candidat_id = ? AND active = 1";
            $stmt = $this->db->prepare($sql);
            $stmt->execute([$candidatId]);
            $result = $stmt->fetch(PDO::FETCH_ASSOC);
            $count = $result['total'] ?? 0;

            // Get candidat info
            $candidatSql = "SELECT id, cin, email, nom, prenom FROM candidats WHERE id = ?";
            $candidatStmt = $this->db->prepare($candidatSql);
            $candidatStmt->execute([$candidatId]);
            $candidat = $candidatStmt->fetch(PDO::FETCH_ASSOC);

            // Determine redirect URL based on count
            $redirectUrl = '';
            if ($count == 0) {
                // No inscriptions - go to create page
                $redirectUrl = $this->inscriptionCreate;
            } elseif ($count == 1) {
                // One inscription - go to create page with existing data
                // Get the inscription ID
                $insSql = "SELECT id FROM inscriptions WHERE candidat_id = ? AND active = 1 LIMIT 1";
                $insStmt = $this->db->prepare($insSql);
                $insStmt->execute([$candidatId]);
                $inscription = $insStmt->fetch(PDO::FETCH_ASSOC);
                $redirectUrl = $this->inscriptionCreate . '?id=' . ($inscription['id'] ?? '');
            } else {
                // Multiple inscriptions - go to list page
                $redirectUrl = $this->inscriptionListPage;
            }

            return [
                'inscription_count' => $count,
                'redirect_url' => $redirectUrl,
                'candidat' => $candidat
            ];
        } catch (Exception $e) {
            error_log('Error checking candidat inscriptions: ' . $e->getMessage());
            return [
                'inscription_count' => 0,
                'redirect_url' => $this->inscriptionCreate,
                'candidat' => null
            ];
        }
    }


    /**
     * Mot de passe oublié :
     * - Cherche l'étudiant par Email
     * - Génère un nouveau mot de passe aléatoire
     * - Le crypte et met à jour la base de données
     * - Envoie le nouveau mot de passe par email
     */
    public function forgotPassword($email)
    {
        // 1. Chercher l'étudiant par Email
        $sql = "SELECT id, email, nom, prenom FROM {$this->table} WHERE email = :email";
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute(['email' => $email]);
        $candidat = $stmt->fetch(PDO::FETCH_ASSOC);

        // 2. Email non trouvé → retourner une erreur
        if (!$candidat) {
            return [
                'success' => false,
                'message' => 'Aucun compte trouvé avec cet Email.'
            ];
        }

        // 3. Générer un nouveau mot de passe aléatoire (8 caractères)
        $newPassword = $this->generatePassword();

        // 4. Crypter le mot de passe avec password_hash()
        $hashedPassword = password_hash($newPassword, PASSWORD_DEFAULT);

        // 5. Mettre à jour le mot de passe dans la base de données
        $sqlUpdate = "UPDATE {$this->table} SET password = :password WHERE id = :id";
        $stmtUpdate = $this->pdo->prepare($sqlUpdate);
        $stmtUpdate->execute([
            'password' => $hashedPassword,
            'id' => $candidat['id']
        ]);

        // 6. Envoyer l'email avec le nouveau mot de passe
        $emailEnvoye = $this->sendPasswordEmail(
            $candidat['email'],
            $candidat['prenom'] . ' ' . $candidat['nom'],
            $newPassword
        );

        // 7. Retourner la réponse avec le nouveau mot de passe (affiché aussi à l'écran)
        if ($emailEnvoye) {
            return [
                'success' => true,
                'message' => 'Un email a été envoyé à ' . $candidat['email'] . ' avec votre nouveau mot de passe.',
                'new_password' => $newPassword
            ];
        } else {
            // Email échoué (normal en local) → on affiche le mot de passe à l'écran
            return [
                'success' => true,
                'message' => 'Mot de passe réinitialisé avec succès. (Email non envoyé en local, notez le mot de passe ci-dessous)',
                'new_password' => $newPassword
            ];
        }
    }

    /**
     * Génère un mot de passe aléatoire de 8 caractères
     * Contient : lettres majuscules, minuscules et chiffres
     */
    private function generatePassword($length = 8)
    {
        $chars = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ23456789';
        $password = '';
        $max = strlen($chars) - 1;
        for ($i = 0; $i < $length; $i++) {
            $password .= $chars[random_int(0, $max)];
        }
        return $password;
    }

    /**
     * Envoie un email avec le nouveau mot de passe
     * Utilise la fonction mail() native de PHP
     * (Fonctionne en production avec un serveur mail configuré)
     */

    private function sendPasswordEmail($email, $fullName, $newPassword)
    {
        $subject = 'Réinitialisation de votre mot de passe - EST';

        $message = "Bonjour $fullName,\r\n\r\n"
            . "Votre mot de passe a été réinitialisé avec succès.\r\n\r\n"
            . "Votre nouveau mot de passe : $newPassword\r\n\r\n"
            . "Connectez-vous sur : http://localhost/est-concours/app/cnx/candidat/login/\r\n\r\n"
            . "Nous vous conseillons de changer ce mot de passe après votre connexion.\r\n\r\n"
            . "Cordialement,\r\n"
            . "L'équipe EST Concours";

        $headers = "From: noreply@est-concours.ma\r\n";
        $headers .= "Reply-To: noreply@est-concours.ma\r\n";
        $headers .= "Content-Type: text/plain; charset=UTF-8\r\n";

        return mail($email, $subject, $message, $headers);
    }

    public function updateCandidatWithPassword($id, $data)
    {
        $currentCandidat = $this->findOne($id);
        if (!empty($data['new_password'])) {
            if (empty($data['current_password']) || !password_verify($data['current_password'], $currentCandidat['password'])) {
                return ['success' => false, 'message' => 'Mot de passe actuel incorrect ou vide'];
            }
            if ($data['new_password'] !== $data['confirm_password']) {
                return ['success' => false, 'message' => 'Les nouveaux mots de passe ne correspondent pas'];
            }
            $data['password'] = password_hash($data['new_password'], PASSWORD_DEFAULT);
        }

        unset($data['current_password'], $data['new_password'], $data['confirm_password']);

        $result = $this->update($id, $data);
        return ['success' => (bool)$result, 'message' => $result ? 'Mise à jour réussie' : 'Erreur lors de la mise à jour'];
    }

}

?>
