<?php
/**
 * Service d'envoi de notifications MQTT pour le chat
 * 
 * Ce script gère l'envoi des notifications via MQTT depuis le backend PHP
 */

require_once 'vendor/autoload.php'; // PhpMqtt

use PhpMqtt\Client\MqttClient;
use PhpMqtt\Client\ConnectionSettings;

class MqttNotificationSender {
    private $mqtt;
    private $db;
    private $config;

    public function __construct($dbConnection, $mqttConfig) {
        $this->db = $dbConnection;
        $this->config = $mqttConfig;
        
        // Initialiser le client MQTT
        $this->initializeMqttClient();
    }

    private function initializeMqttClient() {
        $this->mqtt = new MqttClient(
            $this->config['host'], 
            $this->config['port'],
            'geosector_api_' . uniqid(), // Client ID unique
            MqttClient::MQTT_3_1_1
        );

        $connectionSettings = (new ConnectionSettings)
            ->setUsername($this->config['username'])
            ->setPassword($this->config['password'])
            ->setKeepAliveInterval(60)
            ->setConnectTimeout(30)
            ->setUseTls($this->config['use_ssl'] ?? false);

        $this->mqtt->connect($connectionSettings, true);
    }

    /**
     * Envoie une notification pour un nouveau message
     */
    public function sendMessageNotification($receiverId, $senderId, $messageId, $content, $conversationId) {
        try {
            // Vérifier les préférences de notification
            $settings = $this->getUserNotificationSettings($receiverId);
            
            if (!$this->shouldSendNotification($settings, $conversationId)) {
                return ['status' => 'skipped', 'reason' => 'notification_settings'];
            }

            // Obtenir les informations de l'expéditeur
            $sender = $this->getSenderInfo($senderId);
            
            // Obtenir le nom de la conversation
            $conversationName = $this->getConversationName($conversationId, $receiverId);

            // Préparer le payload de la notification
            $payload = [
                'type' => 'chat_message',
                'messageId' => $messageId,
                'conversationId' => $conversationId,
                'senderId' => $senderId,
                'senderName' => $sender['name'] ?? 'Utilisateur',
                'content' => $settings['show_preview'] ? $content : 'Nouveau message',
                'conversationName' => $conversationName,
                'timestamp' => time(),
            ];

            // Définir le topic MQTT
            $topic = sprintf('chat/user/%s/messages', $receiverId);

            // Publier le message
            $this->mqtt->publish($topic, json_encode($payload), 1);

            // Enregistrer la notification dans la base de données
            $this->saveNotificationToDatabase($receiverId, $messageId, $conversationId, $payload);

            return [
                'status' => 'success',
                'topic' => $topic
            ];

        } catch (Exception $e) {
            return [
                'status' => 'error',
                'reason' => $e->getMessage()
            ];
        }
    }

    /**
     * Envoie une annonce à plusieurs utilisateurs
     */
    public function sendBroadcastAnnouncement($audienceTargets, $messageId, $title, $content, $conversationId) {
        $results = [];
        $userIds = $this->resolveAudienceTargets($audienceTargets);

        foreach ($userIds as $userId) {
            // Préparer le payload pour l'annonce
            $payload = [
                'type' => 'announcement',
                'messageId' => $messageId,
                'conversationId' => $conversationId,
                'title' => $title,
                'content' => $content,
                'timestamp' => time(),
            ];

            // Envoyer à chaque utilisateur
            $topic = sprintf('chat/user/%s/messages', $userId);
            
            try {
                $this->mqtt->publish($topic, json_encode($payload), 1);
                $results[$userId] = ['status' => 'success'];
                
                // Enregistrer la notification
                $this->saveNotificationToDatabase($userId, $messageId, $conversationId, $payload);
            } catch (Exception $e) {
                $results[$userId] = ['status' => 'error', 'reason' => $e->getMessage()];
            }
        }

        // Publier aussi sur le topic général des annonces
        $this->mqtt->publish('chat/announcement', json_encode($payload), 1);

        return $results;
    }

    /**
     * Envoie une notification à une conversation spécifique
     */
    public function sendConversationNotification($conversationId, $messageId, $senderId, $content) {
        $participants = $this->getConversationParticipants($conversationId);
        
        foreach ($participants as $participant) {
            if ($participant['id'] !== $senderId) {
                $this->sendMessageNotification(
                    $participant['id'], 
                    $senderId, 
                    $messageId, 
                    $content, 
                    $conversationId
                );
            }
        }
    }

    /**
     * Vérifie si une notification doit être envoyée
     */
    private function shouldSendNotification($settings, $conversationId) {
        if (!$settings['enable_notifications']) {
            return false;
        }

        if (in_array($conversationId, $settings['muted_conversations'])) {
            return false;
        }

        if ($settings['do_not_disturb'] && $this->isInDoNotDisturbPeriod($settings)) {
            return false;
        }

        return true;
    }

    /**
     * Récupère les paramètres de notification de l'utilisateur
     */
    private function getUserNotificationSettings($userId) {
        $stmt = $this->db->prepare("
            SELECT * FROM notification_settings 
            WHERE user_id = ?
        ");
        
        $stmt->execute([$userId]);
        $result = $stmt->fetch(PDO::FETCH_ASSOC);

        // Valeurs par défaut si pas de préférences
        return $result ?: [
            'enable_notifications' => true,
            'show_preview' => true,
            'muted_conversations' => [],
            'do_not_disturb' => false,
            'do_not_disturb_start' => null,
            'do_not_disturb_end' => null,
        ];
    }

    /**
     * Vérifie si on est dans la période "Ne pas déranger"
     */
    private function isInDoNotDisturbPeriod($settings) {
        if (!$settings['do_not_disturb']) {
            return false;
        }

        $now = new DateTime();
        $start = new DateTime($settings['do_not_disturb_start']);
        $end = new DateTime($settings['do_not_disturb_end']);

        if ($start < $end) {
            return $now >= $start && $now <= $end;
        } else {
            // Période qui chevauche minuit
            return $now >= $start || $now <= $end;
        }
    }

    /**
     * Enregistre la notification dans la base de données
     */
    private function saveNotificationToDatabase($userId, $messageId, $conversationId, $payload) {
        $stmt = $this->db->prepare("
            INSERT INTO chat_notifications 
            (fk_user, fk_message, fk_room, type, contenu, statut)
            VALUES (?, ?, ?, ?, ?, 'non_lue')
        ");
        
        $stmt->execute([
            $userId,
            $messageId,
            $conversationId,
            $payload['type'],
            json_encode($payload)
        ]);
    }

    /**
     * Récupère les informations de l'expéditeur
     */
    private function getSenderInfo($senderId) {
        $stmt = $this->db->prepare("
            SELECT id, name, username 
            FROM users 
            WHERE id = ?
        ");
        
        $stmt->execute([$senderId]);
        return $stmt->fetch(PDO::FETCH_ASSOC);
    }

    /**
     * Récupère le nom de la conversation
     */
    private function getConversationName($conversationId, $userId) {
        $stmt = $this->db->prepare("
            SELECT title 
            FROM chat_rooms 
            WHERE id = ?
        ");
        
        $stmt->execute([$conversationId]);
        return $stmt->fetchColumn();
    }

    /**
     * Récupère les participants d'une conversation
     */
    private function getConversationParticipants($conversationId) {
        $stmt = $this->db->prepare("
            SELECT id_user as id, role 
            FROM chat_participants 
            WHERE id_room = ? AND notification_activee = 1
        ");
        
        $stmt->execute([$conversationId]);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    /**
     * Résout les cibles d'audience en une liste d'IDs utilisateur
     */
    private function resolveAudienceTargets($targets) {
        $userIds = [];
        
        foreach ($targets as $target) {
            switch ($target['target_type']) {
                case 'all':
                    $stmt = $this->db->query("SELECT id FROM users WHERE chk_active = 1");
                    $userIds = array_merge($userIds, $stmt->fetchAll(PDO::FETCH_COLUMN));
                    break;
                    
                case 'role':
                    $stmt = $this->db->prepare("SELECT id FROM users WHERE fk_role = ?");
                    $stmt->execute([$target['role_filter']]);
                    $userIds = array_merge($userIds, $stmt->fetchAll(PDO::FETCH_COLUMN));
                    break;
                    
                case 'entity':
                    $stmt = $this->db->prepare("SELECT id FROM users WHERE fk_entite = ?");
                    $stmt->execute([$target['entity_filter']]);
                    $userIds = array_merge($userIds, $stmt->fetchAll(PDO::FETCH_COLUMN));
                    break;
                    
                case 'combined':
                    $stmt = $this->db->prepare("
                        SELECT id FROM users 
                        WHERE fk_role = ? AND fk_entite = ?
                    ");
                    $stmt->execute([$target['role_filter'], $target['entity_filter']]);
                    $userIds = array_merge($userIds, $stmt->fetchAll(PDO::FETCH_COLUMN));
                    break;
            }
        }
        
        return array_unique($userIds);
    }

    /**
     * Ferme la connexion MQTT
     */
    public function disconnect() {
        if ($this->mqtt) {
            $this->mqtt->disconnect();
        }
    }
}
