#!/usr/bin/env php
<?php

/**
 * Script CRON pour traiter la queue d'emails
 * Envoie les emails en attente dans la table email_queue
 * 
 * À exécuter toutes les 5 minutes via crontab :
 * Exemple: [asterisk]/5 [asterisk] [asterisk] [asterisk] [asterisk] /usr/bin/php /path/to/api/scripts/cron/process_email_queue.php
 */

declare(strict_types=1);

// Configuration
define('MAX_ATTEMPTS', 3);
define('BATCH_SIZE', 50);
define('LOCK_FILE', '/tmp/process_email_queue.lock');

// Empêcher l'exécution multiple simultanée
if (file_exists(LOCK_FILE)) {
    $lockTime = filemtime(LOCK_FILE);
    // Si le lock a plus de 30 minutes, on le supprime (processus probablement bloqué)
    if (time() - $lockTime > 1800) {
        unlink(LOCK_FILE);
    } else {
        die("Le processus est déjà en cours d'exécution\n");
    }
}

// Créer le fichier de lock
file_put_contents(LOCK_FILE, getmypid());

// Enregistrer un handler pour supprimer le lock en cas d'arrêt
register_shutdown_function(function() {
    if (file_exists(LOCK_FILE)) {
        unlink(LOCK_FILE);
    }
});

// Simuler l'environnement web pour AppConfig en CLI
if (php_sapi_name() === 'cli') {
    // Détecter l'environnement basé sur le hostname ou un paramètre
    $hostname = gethostname();
    if (strpos($hostname, 'pra') !== false) {
        $_SERVER['SERVER_NAME'] = 'app3.geosector.fr';
    } elseif (strpos($hostname, 'rca') !== false) {
        $_SERVER['SERVER_NAME'] = 'rapp.geosector.fr';
    } else {
        $_SERVER['SERVER_NAME'] = 'dapp.geosector.fr'; // DVA par défaut
    }

    $_SERVER['HTTP_HOST'] = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'];
    $_SERVER['REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1';
    
    // Définir getallheaders si elle n'existe pas (CLI)
    if (!function_exists('getallheaders')) {
        function getallheaders() {
            return [];
        }
    }
}

// Chargement de l'environnement
require_once __DIR__ . '/../../vendor/autoload.php';
require_once __DIR__ . '/../../src/Config/AppConfig.php';
require_once __DIR__ . '/../../src/Core/Database.php';
require_once __DIR__ . '/../../src/Services/LogService.php';

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;
use App\Services\LogService;

try {
    // Initialisation de la configuration
    $appConfig = AppConfig::getInstance();
    $dbConfig = $appConfig->getDatabaseConfig();
    
    // Initialiser la base de données avec la configuration
    Database::init($dbConfig);
    $db = Database::getInstance();
    
    // Log uniquement si mode debug activé
    // LogService::log('Démarrage du processeur de queue d\'emails', [
    //     'level' => 'info',
    //     'script' => 'process_email_queue.php'
    // ]);
    
    // Récupérer les emails en attente
    $stmt = $db->prepare('
        SELECT id, fk_pass, to_email, subject, body, headers, attempts
        FROM email_queue
        WHERE status = ? AND attempts < ?
        ORDER BY created_at ASC
        LIMIT ?
    ');
    
    $stmt->execute(['pending', MAX_ATTEMPTS, BATCH_SIZE]);
    $emails = $stmt->fetchAll(PDO::FETCH_ASSOC);
    
    if (empty($emails)) {
        // Ne pas logger quand il n'y a rien à faire (toutes les 5 minutes)
        // LogService::log('Aucun email en attente dans la queue', [
        //     'level' => 'debug'
        // ]);
        exit(0);
    }
    
    LogService::log('Emails à traiter', [
        'level' => 'info',
        'count' => count($emails)
    ]);
    
    // Configuration SMTP
    $smtpConfig = $appConfig->getSmtpConfig();
    $emailConfig = $appConfig->getEmailConfig();
    
    $successCount = 0;
    $failureCount = 0;
    
    // Traiter chaque email
    foreach ($emails as $emailData) {
        $emailId = $emailData['id'];
        $passageId = $emailData['fk_pass'];
        
        try {
            // Incrémenter le compteur de tentatives
            $stmt = $db->prepare('UPDATE email_queue SET attempts = attempts + 1 WHERE id = ?');
            $stmt->execute([$emailId]);
            
            // Créer l'instance PHPMailer
            $mail = new PHPMailer(true);
            
            // Configuration du serveur SMTP
            $mail->isSMTP();
            $mail->Host = $smtpConfig['host'];
            $mail->SMTPAuth = $smtpConfig['auth'] ?? true;
            $mail->Username = $smtpConfig['user'];
            $mail->Password = $smtpConfig['pass'];
            $mail->SMTPSecure = $smtpConfig['secure'];
            $mail->Port = $smtpConfig['port'];
            $mail->CharSet = 'UTF-8';
            
            // Configuration de l'expéditeur
            $fromName = 'Amicale Sapeurs-Pompiers'; // Nom par défaut
            $mail->setFrom($emailConfig['from'], $fromName);
            
            // Destinataire
            $mail->addAddress($emailData['to_email']);
            
            // Sujet
            $mail->Subject = $emailData['subject'];
            
            // Headers personnalisés si présents
            if (!empty($emailData['headers'])) {
                // Les headers contiennent déjà les informations MIME pour la pièce jointe
                // On doit extraire le boundary et reconstruire le message
                if (preg_match('/boundary="([^"]+)"/', $emailData['headers'], $matches)) {
                    $boundary = $matches[1];
                    
                    // Le body contient déjà le message complet avec pièce jointe
                    $mail->isHTML(false);
                    $mail->Body = $emailData['body'];
                    
                    // Extraire le contenu HTML et la pièce jointe
                    $parts = explode("--$boundary", $emailData['body']);
                    
                    foreach ($parts as $part) {
                        if (strpos($part, 'Content-Type: text/html') !== false) {
                            // Extraire le contenu HTML
                            $htmlContent = trim(substr($part, strpos($part, "\r\n\r\n") + 4));
                            $mail->isHTML(true);
                            $mail->Body = $htmlContent;
                        } elseif (strpos($part, 'Content-Type: application/pdf') !== false) {
                            // Extraire le PDF encodé en base64
                            if (preg_match('/filename="([^"]+)"/', $part, $fileMatches)) {
                                $filename = $fileMatches[1];
                                $pdfContent = trim(substr($part, strpos($part, "\r\n\r\n") + 4));
                                // Supprimer les retours à la ligne du base64
                                $pdfContent = str_replace(["\r", "\n"], '', $pdfContent);
                                
                                // Ajouter la pièce jointe
                                $mail->addStringAttachment(
                                    base64_decode($pdfContent),
                                    $filename,
                                    'base64',
                                    'application/pdf'
                                );
                            }
                        }
                    }
                }
            } else {
                // Email simple sans pièce jointe
                $mail->isHTML(true);
                $mail->Body = $emailData['body'];
            }
            
            // Ajouter une copie si configuré
            if (!empty($emailConfig['contact'])) {
                $mail->addBCC($emailConfig['contact']);
            }
            
            // Envoyer l'email
            if ($mail->send()) {
                // Marquer comme envoyé
                $stmt = $db->prepare('
                    UPDATE email_queue 
                    SET status = ?, sent_at = NOW() 
                    WHERE id = ?
                ');
                $stmt->execute(['sent', $emailId]);
                
                // Mettre à jour le passage si nécessaire
                if ($passageId > 0) {
                    $stmt = $db->prepare('
                        UPDATE ope_pass 
                        SET date_sent_recu = NOW(), chk_email_sent = 1 
                        WHERE id = ?
                    ');
                    $stmt->execute([$passageId]);
                }
                
                $successCount++;
                
                LogService::log('Email envoyé avec succès', [
                    'level' => 'info',
                    'emailId' => $emailId,
                    'passageId' => $passageId,
                    'to' => $emailData['to_email']
                ]);
            } else {
                throw new Exception('Échec de l\'envoi');
            }
            
        } catch (Exception $e) {
            $failureCount++;
            
            LogService::log('Erreur lors de l\'envoi de l\'email', [
                'level' => 'error',
                'emailId' => $emailId,
                'passageId' => $passageId,
                'error' => $e->getMessage(),
                'attempts' => $emailData['attempts'] + 1
            ]);
            
            // Si on a atteint le nombre max de tentatives, marquer comme échoué
            if ($emailData['attempts'] + 1 >= MAX_ATTEMPTS) {
                $stmt = $db->prepare('
                    UPDATE email_queue 
                    SET status = ?, error_message = ?
                    WHERE id = ?
                ');
                $stmt->execute(['failed', $e->getMessage(), $emailId]);
                
                LogService::log('Email marqué comme échoué après ' . MAX_ATTEMPTS . ' tentatives', [
                    'level' => 'warning',
                    'emailId' => $emailId,
                    'passageId' => $passageId
                ]);
            }
        }
        
        // Pause courte entre chaque email pour éviter la surcharge
        usleep(500000); // 0.5 seconde
    }
    
    // Logger uniquement s'il y avait des emails à traiter
    if (count($emails) > 0) {
        LogService::log('Traitement de la queue terminé', [
            'level' => 'info',
            'success' => $successCount,
            'failures' => $failureCount,
            'total' => count($emails)
        ]);
    }
    
} catch (Exception $e) {
    LogService::log('Erreur fatale dans le processeur de queue', [
        'level' => 'critical',
        'error' => $e->getMessage(),
        'trace' => $e->getTraceAsString()
    ]);
    
    // Supprimer le lock en cas d'erreur
    if (file_exists(LOCK_FILE)) {
        unlink(LOCK_FILE);
    }
    
    exit(1);
}

// Nettoyer les vieux emails traités (optionnel)
try {
    // Supprimer les emails envoyés de plus de 30 jours
    $stmt = $db->prepare('
        DELETE FROM email_queue 
        WHERE status = ? AND sent_at < DATE_SUB(NOW(), INTERVAL 30 DAY)
    ');
    $stmt->execute(['sent']);
    
    $deleted = $stmt->rowCount();
    if ($deleted > 0) {
        LogService::log('Nettoyage des anciens emails', [
            'level' => 'info',
            'deleted' => $deleted
        ]);
    }
    
} catch (Exception $e) {
    LogService::log('Erreur lors du nettoyage des anciens emails', [
        'level' => 'warning',
        'error' => $e->getMessage()
    ]);
}

// Supprimer le lock
if (file_exists(LOCK_FILE)) {
    unlink(LOCK_FILE);
}

echo "Traitement terminé : $successCount envoyés, $failureCount échecs\n";
exit(0);