//! Gestion unifiée des salons, messages directs et modération
//!
//! Ce module fournit une interface unifiée pour:
//! - Gestion des salons (création, suppression, permissions)
//! - Messages directs entre utilisateurs
//! - Système de modération avancé
//! - Gestion des rôles et permissions
//! - Intégration avec les métriques et logs

use crate::authentication::{Role, UserSession};
use crate::error::{ChatError, Result};
use crate::prometheus_metrics::PrometheusMetrics;
use crate::structured_logging::chat_logs;
use chrono::{DateTime, Utc};
use std::time::Duration;
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use tokio::sync::RwLock;
use uuid::Uuid;

/// Types de salons
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum RoomType {
    /// Salon public - visible par tous
    Public,
    /// Salon privé - invitation uniquement
    Private,
    /// Salon direct - conversation entre 2 utilisateurs
    Direct,
    /// Salon système - géré par le système
    System,
}

/// Permissions dans un salon
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub enum RoomPermission {
    /// Lire les messages
    Read,
    /// Envoyer des messages
    Write,
    /// Modifier les messages
    Edit,
    /// Supprimer les messages
    Delete,
    /// Inviter des utilisateurs
    Invite,
    /// Gérer le salon
    Manage,
    /// Modérer le salon
    Moderate,
}

/// Statut d'un salon
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum RoomStatus {
    /// Salon actif
    Active,
    /// Salon archivé
    Archived,
    /// Salon supprimé
    Deleted,
    /// Salon suspendu
    Suspended,
}

/// Configuration d'un salon
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RoomConfig {
    /// Nom du salon
    pub name: String,
    /// Description du salon
    pub description: Option<String>,
    /// Type du salon
    pub room_type: RoomType,
    /// Permissions par défaut
    pub default_permissions: HashSet<RoomPermission>,
    /// Limite de membres (None = illimitée)
    pub max_members: Option<u32>,
    /// Activer l'historique des messages
    pub enable_history: bool,
    /// Activer les réactions
    pub enable_reactions: bool,
    /// Activer les mentions
    pub enable_mentions: bool,
    /// Activer les fils de discussion
    pub enable_threads: bool,
    /// Mots-clés interdits
    pub forbidden_words: HashSet<String>,
    /// Activer la modération automatique
    pub auto_moderation: bool,
}

impl Default for RoomConfig {
    fn default() -> Self {
        Self {
            name: "Nouveau salon".to_string(),
            description: None,
            room_type: RoomType::Public,
            default_permissions: HashSet::from([RoomPermission::Read, RoomPermission::Write]),
            max_members: Some(1000),
            enable_history: true,
            enable_reactions: true,
            enable_mentions: true,
            enable_threads: true,
            forbidden_words: HashSet::new(),
            auto_moderation: false,
        }
    }
}

/// Salon de chat
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Room {
    /// ID unique du salon
    pub id: Uuid,
    /// Configuration du salon
    pub config: RoomConfig,
    /// Créateur du salon
    pub creator_id: i32,
    /// Date de création
    pub created_at: DateTime<Utc>,
    /// Date de dernière activité
    pub last_activity: DateTime<Utc>,
    /// Statut du salon
    pub status: RoomStatus,
    /// Membres du salon (user_id -> permissions)
    pub members: HashMap<i32, HashSet<RoomPermission>>,
    /// Modérateurs du salon
    pub moderators: HashSet<i32>,
    /// Administrateurs du salon
    pub administrators: HashSet<i32>,
    /// Messages épinglés
    pub pinned_messages: Vec<Uuid>,
    /// Tags du salon
    pub tags: HashSet<String>,
}

impl Room {
    /// Crée un nouveau salon
    pub fn new(creator_id: i32, config: RoomConfig) -> Self {
        let now = Utc::now();
        Self {
            id: Uuid::new_v4(),
            config,
            creator_id,
            created_at: now,
            last_activity: now,
            status: RoomStatus::Active,
            members: HashMap::new(),
            moderators: HashSet::new(),
            administrators: HashSet::new(),
            pinned_messages: Vec::new(),
            tags: HashSet::new(),
        }
    }

    /// Ajoute un membre au salon
    pub fn add_member(&mut self, user_id: i32, permissions: HashSet<RoomPermission>) {
        self.members.insert(user_id, permissions);
        self.last_activity = Utc::now();
    }

    /// Retire un membre du salon
    pub fn remove_member(&mut self, user_id: i32) {
        self.members.remove(&user_id);
        self.moderators.remove(&user_id);
        self.administrators.remove(&user_id);
        self.last_activity = Utc::now();
    }

    /// Vérifie si un utilisateur a une permission spécifique
    pub fn has_permission(&self, user_id: i32, permission: &RoomPermission) -> bool {
        // L'administrateur du salon a toutes les permissions
        if self.administrators.contains(&user_id) {
            return true;
        }

        // Vérifier les permissions du membre
        if let Some(member_permissions) = self.members.get(&user_id) {
            member_permissions.contains(permission)
        } else {
            false
        }
    }

    /// Vérifie si un utilisateur peut envoyer des messages
    pub fn can_send_messages(&self, user_id: i32) -> bool {
        self.has_permission(user_id, &RoomPermission::Write)
    }

    /// Vérifie si un utilisateur peut modérer
    pub fn can_moderate(&self, user_id: i32) -> bool {
        self.administrators.contains(&user_id)
            || self.moderators.contains(&user_id)
            || self.has_permission(user_id, &RoomPermission::Moderate)
    }

    /// Ajoute un modérateur
    pub fn add_moderator(&mut self, user_id: i32) -> Result<()> {
        if !self.members.contains_key(&user_id) {
            return Err(ChatError::validation_error(
                "Utilisateur n'est pas membre du salon",
            ));
        }

        self.moderators.insert(user_id);
        self.last_activity = Utc::now();
        Ok(())
    }

    /// Retire un modérateur
    pub fn remove_moderator(&mut self, user_id: i32) {
        self.moderators.remove(&user_id);
        self.last_activity = Utc::now();
    }

    /// Épingle un message
    pub fn pin_message(&mut self, message_id: Uuid) -> Result<()> {
        if self.pinned_messages.len() >= 10 {
            return Err(ChatError::validation_error("Trop de messages épinglés"));
        }

        if !self.pinned_messages.contains(&message_id) {
            self.pinned_messages.push(message_id);
            self.last_activity = Utc::now();
        }

        Ok(())
    }

    /// Désépingle un message
    pub fn unpin_message(&mut self, message_id: Uuid) {
        self.pinned_messages.retain(|&id| id != message_id);
        self.last_activity = Utc::now();
    }

    /// Met à jour la dernière activité
    pub fn update_activity(&mut self) {
        self.last_activity = Utc::now();
    }

    /// Archive le salon
    pub fn archive(&mut self) {
        self.status = RoomStatus::Archived;
        self.last_activity = Utc::now();
    }

    /// Supprime le salon
    pub fn delete(&mut self) {
        self.status = RoomStatus::Deleted;
        self.last_activity = Utc::now();
    }
}

/// Message de chat
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChatMessage {
    /// ID unique du message
    pub id: Uuid,
    /// ID du salon ou de la conversation
    pub room_id: Uuid,
    /// ID de l'expéditeur
    pub sender_id: i32,
    /// Nom d'utilisateur de l'expéditeur
    pub sender_username: String,
    /// Contenu du message
    pub content: String,
    /// Type de message
    pub message_type: MessageType,
    /// Message parent (pour les fils de discussion)
    pub parent_message_id: Option<Uuid>,
    /// Date d'envoi
    pub sent_at: DateTime<Utc>,
    /// Date de modification
    pub edited_at: Option<DateTime<Utc>>,
    /// Message supprimé
    pub deleted: bool,
    /// Réactions au message
    pub reactions: HashMap<String, Vec<i32>>,
    /// Mentions dans le message
    pub mentions: Vec<i32>,
    /// Fichiers joints
    pub attachments: Vec<Attachment>,
    /// Métadonnées du message
    pub metadata: HashMap<String, String>,
}

/// Types de messages
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum MessageType {
    /// Message texte normal
    Text,
    /// Message système
    System,
    /// Message de bienvenue
    Welcome,
    /// Message de modération
    Moderation,
    /// Message de fichier
    File,
    /// Message d'image
    Image,
    /// Message de code
    Code,
    /// Message de commande
    Command,
}

/// Fichier joint
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Attachment {
    /// ID du fichier
    pub id: Uuid,
    /// Nom du fichier
    pub filename: String,
    /// Type MIME
    pub mime_type: String,
    /// Taille en bytes
    pub size_bytes: u64,
    /// URL de téléchargement
    pub download_url: String,
    /// Date d'upload
    pub uploaded_at: DateTime<Utc>,
}

/// Action de modération
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModerationAction {
    /// ID de l'action
    pub id: Uuid,
    /// Type d'action
    pub action_type: ModerationActionType,
    /// ID du modérateur
    pub moderator_id: i32,
    /// ID de l'utilisateur ciblé
    pub target_user_id: Option<i32>,
    /// ID du message ciblé
    pub target_message_id: Option<Uuid>,
    /// ID du salon
    pub room_id: Uuid,
    /// Raison de l'action
    pub reason: String,
    /// Durée de la sanction (si applicable)
    pub duration: Option<Duration>,
    /// Date de l'action
    pub created_at: DateTime<Utc>,
    /// Action active
    pub active: bool,
}

/// Types d'actions de modération
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum ModerationActionType {
    /// Avertissement
    Warning,
    /// Suppression de message
    DeleteMessage,
    /// Modification de message
    EditMessage,
    /// Bannissement temporaire
    TemporaryBan,
    /// Bannissement permanent
    PermanentBan,
    /// Mute temporaire
    TemporaryMute,
    /// Mute permanent
    PermanentMute,
    /// Kick du salon
    Kick,
    /// Suspension du salon
    SuspendRoom,
    /// Suppression du salon
    DeleteRoom,
}

/// Gestionnaire de chat unifié
pub struct ChatManager {
    /// Salons actifs
    rooms: Arc<RwLock<HashMap<Uuid, Room>>>,
    /// Messages par salon
    messages: Arc<RwLock<HashMap<Uuid, Vec<ChatMessage>>>>,
    /// Actions de modération
    moderation_actions: Arc<RwLock<Vec<ModerationAction>>>,
    /// Métriques Prometheus
    metrics: Option<Arc<PrometheusMetrics>>,
}

impl ChatManager {
    /// Crée un nouveau gestionnaire de chat
    pub fn new(metrics: Option<Arc<PrometheusMetrics>>) -> Self {
        Self {
            rooms: Arc::new(RwLock::new(HashMap::new())),
            messages: Arc::new(RwLock::new(HashMap::new())),
            moderation_actions: Arc::new(RwLock::new(Vec::new())),
            metrics,
        }
    }

    /// Crée un nouveau salon
    pub async fn create_room(
        &self,
        creator_id: i32,
        creator_username: &str,
        config: RoomConfig,
    ) -> Result<Uuid> {
        let room = Room::new(creator_id, config.clone());
        let room_id = room.id;

        // Ajouter le créateur comme administrateur
        let mut room = room;
        room.administrators.insert(creator_id);
        room.add_member(creator_id, room.config.default_permissions.clone());

        // Sauvegarder le salon
        {
            let mut rooms = self.rooms.write().await;
            rooms.insert(room_id, room);
        }

        // Enregistrer les métriques
        if let Some(metrics) = &self.metrics {
            metrics.record_room_created();
            metrics.update_active_rooms(self.get_active_rooms_count().await);
        }

        chat_logs::room_created(
            &room_id.to_string(),
            &config.name,
            creator_id,
            creator_username,
        );

        Ok(room_id)
    }

    /// Supprime un salon
    pub async fn delete_room(
        &self,
        room_id: Uuid,
        deleter_id: i32,
        deleter_username: &str,
    ) -> Result<()> {
        let room_name = {
            let rooms = self.rooms.read().await;
            let room = rooms
                .get(&room_id)
                .ok_or_else(|| ChatError::validation_error("Salon non trouvé"))?;

            // Vérifier les permissions
            if !room.administrators.contains(&deleter_id) {
                return Err(ChatError::unauthorized("Permissions insuffisantes"));
            }

            room.config.name.clone()
        };

        // Supprimer le salon
        {
            let mut rooms = self.rooms.write().await;
            if let Some(room) = rooms.get_mut(&room_id) {
                room.delete();
            }
        }

        // Supprimer les messages
        {
            let mut messages = self.messages.write().await;
            messages.remove(&room_id);
        }

        // Enregistrer les métriques
        if let Some(metrics) = &self.metrics {
            metrics.record_room_deleted();
            metrics.update_active_rooms(self.get_active_rooms_count().await);
        }

        chat_logs::room_deleted(
            &room_id.to_string(),
            &room_name,
            deleter_id,
            deleter_username,
        );

        Ok(())
    }

    /// Rejoint un salon
    pub async fn join_room(&self, room_id: Uuid, user_id: i32, username: &str) -> Result<()> {
        let mut rooms = self.rooms.write().await;
        let room = rooms
            .get_mut(&room_id)
            .ok_or_else(|| ChatError::validation_error("Salon non trouvé"))?;

        // Vérifier si le salon est actif
        if room.status != RoomStatus::Active {
            return Err(ChatError::validation_error("Salon non actif"));
        }

        // Vérifier la limite de membres
        if let Some(max_members) = room.config.max_members {
            if room.members.len() >= max_members as usize {
                return Err(ChatError::validation_error("Salon plein"));
            }
        }

        // Ajouter le membre
        room.add_member(user_id, room.config.default_permissions.clone());

        chat_logs::room_created(&room_id.to_string(), &room.config.name, user_id, username);

        Ok(())
    }

    /// Quitte un salon
    pub async fn leave_room(&self, room_id: Uuid, user_id: i32, username: &str) -> Result<()> {
        let mut rooms = self.rooms.write().await;
        let room = rooms
            .get_mut(&room_id)
            .ok_or_else(|| ChatError::validation_error("Salon non trouvé"))?;

        room.remove_member(user_id);

        chat_logs::room_deleted(&room_id.to_string(), &room.config.name, user_id, username);

        Ok(())
    }

    /// Envoie un message dans un salon
    pub async fn send_message(
        &self,
        room_id: Uuid,
        sender_id: i32,
        sender_username: &str,
        content: String,
        message_type: MessageType,
    ) -> Result<Uuid> {
        // Vérifier les permissions
        {
            let rooms = self.rooms.read().await;
            let room = rooms
                .get(&room_id)
                .ok_or_else(|| ChatError::validation_error("Salon non trouvé"))?;

            if !room.can_send_messages(sender_id) {
                return Err(ChatError::unauthorized("Permissions insuffisantes"));
            }
        }

        // Créer le message
        let message = ChatMessage {
            id: Uuid::new_v4(),
            room_id,
            sender_id,
            sender_username: sender_username.to_string(),
            content: content.clone(),
            message_type,
            parent_message_id: None,
            sent_at: Utc::now(),
            edited_at: None,
            deleted: false,
            reactions: HashMap::new(),
            mentions: Vec::new(),
            attachments: Vec::new(),
            metadata: HashMap::new(),
        };

        let message_id = message.id;

        // Sauvegarder le message
        {
            let mut messages = self.messages.write().await;
            messages.entry(room_id).or_default().push(message);
        }

        // Mettre à jour l'activité du salon
        {
            let mut rooms = self.rooms.write().await;
            if let Some(room) = rooms.get_mut(&room_id) {
                room.update_activity();
            }
        }

        // Enregistrer les métriques
        if let Some(metrics) = &self.metrics {
            metrics.record_message_sent("text", "room");
            metrics.record_message_size(content.len() as u64, "text");
        }

        chat_logs::message_sent(
            message_id.to_string(),
            sender_id,
            sender_username,
            &room_id.to_string(),
            "text",
            content.len(),
        );

        Ok(message_id)
    }

    /// Récupère les messages d'un salon
    pub async fn get_room_messages(
        &self,
        room_id: Uuid,
        limit: Option<usize>,
        offset: Option<usize>,
    ) -> Result<Vec<ChatMessage>> {
        let messages = self.messages.read().await;
        let room_messages = messages
            .get(&room_id)
            .ok_or_else(|| ChatError::validation_error("Salon non trouvé"))?;

        let offset = offset.unwrap_or(0);
        let limit = limit.unwrap_or(50).min(100);

        let start = room_messages.len().saturating_sub(offset + limit);
        let end = room_messages.len().saturating_sub(offset);

        Ok(room_messages[start..end].to_vec())
    }

    /// Crée une conversation directe
    pub async fn create_direct_conversation(&self, user1_id: i32, user2_id: i32) -> Result<Uuid> {
        let config = RoomConfig {
            name: format!("DM_{}_{}", user1_id, user2_id),
            room_type: RoomType::Direct,
            max_members: Some(2),
            ..Default::default()
        };

        let room_id = self.create_room(user1_id, "system", config).await?;

        // Ajouter le deuxième utilisateur
        self.join_room(room_id, user2_id, "user").await?;

        Ok(room_id)
    }

    /// Applique une action de modération
    pub async fn apply_moderation_action(&self, action: ModerationAction) -> Result<()> {
        // Sauvegarder l'action
        {
            let mut actions = self.moderation_actions.write().await;
            actions.push(action.clone());
        }

        // Appliquer l'action selon le type
        match action.action_type {
            ModerationActionType::DeleteMessage => {
                if let Some(message_id) = action.target_message_id {
                    self.delete_message(message_id, action.moderator_id).await?;
                }
            }
            ModerationActionType::Kick => {
                if let Some(user_id) = action.target_user_id {
                    self.leave_room(action.room_id, user_id, "moderated")
                        .await?;
                }
            }
            ModerationActionType::SuspendRoom => {
                self.suspend_room(action.room_id, action.moderator_id)
                    .await?;
            }
            _ => {
                // Autres actions de modération
            }
        }

        // Enregistrer les métriques
        if let Some(metrics) = &self.metrics {
            metrics.record_moderation_action(&format!("{:?}", action.action_type));
        }

        Ok(())
    }

    /// Supprime un message
    async fn delete_message(&self, message_id: Uuid, moderator_id: i32) -> Result<()> {
        let mut messages = self.messages.write().await;

        for room_messages in messages.values_mut() {
            if let Some(message) = room_messages.iter_mut().find(|m| m.id == message_id) {
                message.deleted = true;
                message
                    .metadata
                    .insert("deleted_by".to_string(), moderator_id.to_string());
                message
                    .metadata
                    .insert("deleted_at".to_string(), Utc::now().to_rfc3339());
                return Ok(());
            }
        }

        Err(ChatError::validation_error("Message non trouvé"))
    }

    /// Suspend un salon
    async fn suspend_room(&self, room_id: Uuid, _moderator_id: i32) -> Result<()> {
        let mut rooms = self.rooms.write().await;
        if let Some(room) = rooms.get_mut(&room_id) {
            room.status = RoomStatus::Suspended;
            room.last_activity = Utc::now();
        }
        Ok(())
    }

    /// Récupère le nombre de salons actifs
    async fn get_active_rooms_count(&self) -> u64 {
        let rooms = self.rooms.read().await;
        rooms
            .values()
            .filter(|room| room.status == RoomStatus::Active)
            .count() as u64
    }

    /// Récupère les statistiques du chat
    pub async fn get_chat_stats(&self) -> ChatStats {
        let rooms = self.rooms.read().await;
        let messages = self.messages.read().await;

        let total_rooms = rooms.len();
        let active_rooms = rooms
            .values()
            .filter(|room| room.status == RoomStatus::Active)
            .count();

        let total_messages = messages.values().map(|msgs| msgs.len()).sum::<usize>();

        let total_members = rooms.values().map(|room| room.members.len()).sum::<usize>();

        ChatStats {
            total_rooms,
            active_rooms,
            total_messages,
            total_members,
        }
    }
}

/// Statistiques du chat
#[derive(Debug, Clone, Serialize)]
pub struct ChatStats {
    pub total_rooms: usize,
    pub active_rooms: usize,
    pub total_messages: usize,
    pub total_members: usize,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn test_room_creation() {
        let manager = ChatManager::new(None);
        let config = RoomConfig::default();

        let room_id = manager.create_room(1, "testuser", config).await.unwrap();
        assert!(!room_id.is_nil());
    }

    #[tokio::test]
    async fn test_room_permissions() {
        let room = Room::new(1, RoomConfig::default());

        // Le créateur doit avoir toutes les permissions
        assert!(room.can_send_messages(1));
        assert!(room.can_moderate(1));

        // Un utilisateur non membre ne doit pas avoir de permissions
        assert!(!room.can_send_messages(2));
    }

    #[tokio::test]
    async fn test_message_sending() {
        let manager = ChatManager::new(None);
        let config = RoomConfig::default();

        let room_id = manager.create_room(1, "testuser", config).await.unwrap();
        let message_id = manager
            .send_message(
                room_id,
                1,
                "testuser",
                "Hello world".to_string(),
                MessageType::Text,
            )
            .await
            .unwrap();

        assert!(!message_id.is_nil());
    }
}
