//! Service pour l'édition et la suppression de messages
//!
//! Ce module fournit un service centralisé pour gérer l'édition et la suppression
//! de messages avec validation des permissions et mise à jour de la base de données.

use crate::error::{ChatError, Result};
use crate::repository::MessageRepository;
use crate::security::permission::PermissionService;
use sqlx::PgPool;
use tracing::{debug, info, warn};
use uuid::Uuid;

/// Service pour l'édition et la suppression de messages
pub struct MessageEditService {
    message_repo: MessageRepository,
    permission_service: PermissionService,
}

impl MessageEditService {
    /// Crée un nouveau service d'édition de messages
    pub fn new(pool: PgPool) -> Self {
        Self {
            message_repo: MessageRepository::new(pool.clone()),
            permission_service: PermissionService::new(pool),
        }
    }

    /// Édite un message
    ///
    /// # Arguments
    ///
    /// * `user_id` - ID de l'utilisateur qui édite
    /// * `message_id` - ID du message à éditer
    /// * `new_content` - Nouveau contenu du message
    ///
    /// # Returns
    ///
    /// Le message mis à jour
    ///
    /// # Erreurs
    ///
    /// * `ChatError::NotFound` - Message introuvable
    /// * `ChatError::ValidationError` - Message supprimé ou contenu invalide
    /// * `ChatError::InsufficientPermissions` - Permissions insuffisantes
    pub async fn edit_message(
        &self,
        user_id: Uuid,
        message_id: Uuid,
        new_content: &str,
    ) -> Result<crate::models::message::Message> {
        // Validation du contenu
        if new_content.trim().is_empty() {
            return Err(ChatError::validation_error(
                "Le contenu du message ne peut pas être vide",
            ));
        }

        // Limite de longueur (configurable, 4000 caractères par défaut)
        const MAX_CONTENT_LENGTH: usize = 4000;
        if new_content.len() > MAX_CONTENT_LENGTH {
            return Err(ChatError::validation_error(&format!(
                "Le contenu du message ne peut pas dépasser {} caractères",
                MAX_CONTENT_LENGTH
            )));
        }

        // Vérifier que le message existe et n'est pas supprimé
        let message = self.message_repo.get_by_id(message_id).await.map_err(|e| {
            ChatError::internal_error(format!("Erreur lors de la récupération du message: {}", e))
        })?;

        let message =
            message.ok_or_else(|| ChatError::not_found("Message", &message_id.to_string()))?;

        // Vérifier que le contenu a changé
        if message.content == new_content {
            return Err(ChatError::validation_error(
                "Le nouveau contenu doit être différent de l'ancien",
            ));
        }

        // Vérifier les permissions
        self.permission_service
            .can_edit_message(user_id, message_id)
            .await
            .map_err(|e| {
                warn!(
                    user_id = %user_id,
                    message_id = %message_id,
                    error = %e,
                    "Permission refusée pour l'édition du message"
                );
                e
            })?;

        // Mettre à jour le message
        let updated_message = self
            .message_repo
            .update(message_id, new_content)
            .await
            .map_err(|e| {
                ChatError::internal_error(format!(
                    "Erreur lors de la mise à jour du message: {}",
                    e
                ))
            })?;

        info!(
            user_id = %user_id,
            message_id = %message_id,
            conversation_id = %updated_message.conversation_id,
            "Message édité avec succès"
        );

        Ok(updated_message)
    }

    /// Supprime un message (soft delete)
    ///
    /// # Arguments
    ///
    /// * `user_id` - ID de l'utilisateur qui supprime
    /// * `message_id` - ID du message à supprimer
    ///
    /// # Returns
    ///
    /// Le message supprimé (avec is_deleted = true)
    ///
    /// # Erreurs
    ///
    /// * `ChatError::NotFound` - Message introuvable
    /// * `ChatError::InsufficientPermissions` - Permissions insuffisantes
    ///
    /// # Note
    ///
    /// Cette méthode est idempotente : supprimer un message déjà supprimé
    /// retourne OK sans erreur.
    pub async fn delete_message(
        &self,
        user_id: Uuid,
        message_id: Uuid,
    ) -> Result<crate::models::message::Message> {
        // Vérifier que le message existe (même s'il est déjà supprimé)
        let message = self
            .message_repo
            .get_by_id_including_deleted(message_id)
            .await
            .map_err(|e| {
                ChatError::internal_error(format!(
                    "Erreur lors de la récupération du message: {}",
                    e
                ))
            })?;

        let message =
            message.ok_or_else(|| ChatError::not_found("Message", &message_id.to_string()))?;

        // Si déjà supprimé, retourner le message tel quel (idempotent)
        if message.is_deleted {
            debug!(
                user_id = %user_id,
                message_id = %message_id,
                "Message déjà supprimé, opération idempotente"
            );
            return Ok(message);
        }

        // Vérifier les permissions
        self.permission_service
            .can_delete_message(user_id, message_id)
            .await
            .map_err(|e| {
                warn!(
                    user_id = %user_id,
                    message_id = %message_id,
                    error = %e,
                    "Permission refusée pour la suppression du message"
                );
                e
            })?;

        // Supprimer le message (soft delete)
        self.message_repo.delete(message_id).await.map_err(|e| {
            ChatError::internal_error(format!("Erreur lors de la suppression du message: {}", e))
        })?;

        // Récupérer le message supprimé pour le retourner
        let deleted_message = self
            .message_repo
            .get_by_id_including_deleted(message_id)
            .await
            .map_err(|e| {
                ChatError::internal_error(format!(
                    "Erreur lors de la récupération du message supprimé: {}",
                    e
                ))
            })?;

        let deleted_message = deleted_message.ok_or_else(|| {
            ChatError::internal_error(
                "Message supprimé mais introuvable après suppression".to_string(),
            )
        })?;

        info!(
            user_id = %user_id,
            message_id = %message_id,
            conversation_id = %deleted_message.conversation_id,
            "Message supprimé avec succès"
        );

        Ok(deleted_message)
    }
}

#[cfg(test)]
mod tests {

    // Note: Les tests nécessitent une base de données de test
    // Ils sont marqués avec #[ignore] car ils nécessitent une configuration spécifique

    #[tokio::test]
    #[ignore] // Nécessite une base de données de test
    async fn test_edit_message_author() {
        // Ce test nécessite un pool de test et des données de test
        // let pool = create_test_pool().await;
        // let service = MessageEditService::new(pool);
        // let user_id = Uuid::new_v4();
        // let message_id = Uuid::new_v4();
        //
        // // Créer un message
        // let message = service.message_repo.create(...).await.unwrap();
        //
        // // L'auteur peut éditer son message
        // let edited = service.edit_message(user_id, message_id, "Nouveau contenu").await.unwrap();
        // assert_eq!(edited.content, "Nouveau contenu");
        // assert!(edited.is_edited);
    }

    #[tokio::test]
    #[ignore] // Nécessite une base de données de test
    async fn test_delete_message_idempotent() {
        // Ce test nécessite un pool de test
        // let pool = create_test_pool().await;
        // let service = MessageEditService::new(pool);
        // let user_id = Uuid::new_v4();
        // let message_id = Uuid::new_v4();
        //
        // // Supprimer le message
        // let deleted1 = service.delete_message(user_id, message_id).await.unwrap();
        // assert!(deleted1.is_deleted);
        //
        // // Supprimer à nouveau (idempotent)
        // let deleted2 = service.delete_message(user_id, message_id).await.unwrap();
        // assert!(deleted2.is_deleted);
    }
}
