use std::time::{Duration};
use serde::{Serialize, Deserialize};
use crate::error::{ChatError, Result};
use crate::hub::common::ChatHub;
use crate::permissions::Role;
use sqlx::Row;

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum SanctionType {
    Warning,
    Mute,
    Kick,
    TempBan,
    PermaBan,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum SanctionReason {
    Spam,
    Harassment,
    Inappropriate,
    Toxicity,
    RuleViolation,
    Abuse,
    Other(String),
}

#[derive(Debug, Clone, Serialize)]
pub struct Sanction {
    pub id: i32,
    pub user_id: i32,
    pub moderator_id: i32,
    pub sanction_type: SanctionType,
    pub reason: SanctionReason,
    pub message: Option<String>,
    pub duration: Option<Duration>,
    pub created_at: chrono::DateTime<chrono::Utc>,
    pub expires_at: Option<chrono::DateTime<chrono::Utc>>,
    pub is_active: bool,
}

#[derive(Debug, Clone, Serialize)]
pub struct UserModerationRecord {
    pub user_id: i32,
    pub username: String,
    pub sanctions: Vec<Sanction>,
    pub total_warnings: u32,
    pub total_mutes: u32,
    pub total_bans: u32,
    pub reputation_score: i32,
    pub is_currently_banned: bool,
    pub is_currently_muted: bool,
}

/// Système de modération automatique et manuelle
pub struct ModerationSystem {
    hub: std::sync::Arc<ChatHub>,
}

impl ModerationSystem {
    pub fn new(hub: std::sync::Arc<ChatHub>) -> Self {
        Self {
            hub,
        }
    }

    /// Applique une sanction manuelle par un modérateur
    pub async fn apply_sanction(
        &self,
        moderator_id: i32,
        moderator_role: &Role,
        target_user_id: i32,
        sanction_type: SanctionType,
        reason: SanctionReason,
        message: Option<String>,
        duration: Option<Duration>,
    ) -> Result<()> {
        // Vérifier les permissions du modérateur
        self.check_moderator_permissions(moderator_role, &sanction_type)?;

        // Vérifier que l'utilisateur cible existe
        if !self.user_exists(target_user_id).await? {
            return Err(ChatError::configuration_error("Utilisateur cible introuvable"));
        }

        // Calculer l'expiration si durée spécifiée
        let expires_at = duration.map(|d| {
            chrono::Utc::now() + chrono::Duration::from_std(d).unwrap_or(chrono::Duration::zero())
        });

        // Insérer la sanction en base
        let sanction_id = self.insert_sanction(
            target_user_id,
            moderator_id,
            &sanction_type,
            &reason,
            message.as_deref(),
            expires_at,
        ).await?;

        // Appliquer les effets de la sanction
        self.enforce_sanction(target_user_id, &sanction_type, duration).await?;

        // Notifier l'utilisateur sanctionné
        self.notify_user_sanctioned(target_user_id, &sanction_type, &reason, message.as_deref()).await?;

        // Audit log
        tracing::warn!(
            sanction_id = %sanction_id,
            moderator_id = %moderator_id,
            target_user_id = %target_user_id,
            sanction_type = ?sanction_type,
            reason = ?reason,
            duration = ?duration,
            "⚖️ Sanction appliquée"
        );

        Ok(())
    }

    /// Vérification automatique d'un message pour détecter les violations
    pub async fn check_message_auto_moderation(
        &self,
        user_id: i32,
        content: &str,
    ) -> Result<Option<SanctionType>> {
        // Détection de spam basique
        if self.detect_spam(user_id, content).await? {
            let user_record = self.get_user_moderation_record(user_id).await?;
            let sanction_type = self.determine_auto_sanction(&user_record).await?;
            
            if let Some(sanction) = &sanction_type {
                self.apply_sanction(
                    0, // ID système
                    &Role::Admin,
                    user_id,
                    sanction.clone(),
                    SanctionReason::Spam,
                    Some("Sanction automatique - spam détecté".to_string()),
                    Some(Duration::from_secs(3600)), // 1 heure
                ).await?;
            }

            return Ok(sanction_type);
        }

        Ok(None)
    }

    /// Lève une sanction (unban, unmute, etc.)
    pub async fn lift_sanction(
        &self,
        moderator_id: i32,
        moderator_role: &Role,
        target_user_id: i32,
        sanction_type: SanctionType,
    ) -> Result<()> {
        // Vérifier les permissions
        self.check_moderator_permissions(moderator_role, &sanction_type)?;

        // Désactiver la sanction en base
        sqlx::query(
            "UPDATE sanctions SET is_active = false WHERE user_id = $1 AND sanction_type = $2 AND is_active = true"
        )
        .bind(target_user_id)
        .bind(serde_json::to_string(&sanction_type).map_err(|e| ChatError::from_json_error(e))?)
        .execute(&self.hub.db)
        .await
        .map_err(|e| ChatError::from_sqlx_error("database_operation", e))?;

        // Retirer les effets de la sanction
        self.remove_sanction_effects(target_user_id, &sanction_type).await?;

        tracing::info!(
            moderator_id = %moderator_id,
            target_user_id = %target_user_id,
            sanction_type = ?sanction_type,
            "✅ Sanction levée"
        );

        Ok(())
    }

    /// Obtient l'historique de modération d'un utilisateur
    pub async fn get_user_moderation_record(&self, user_id: i32) -> Result<UserModerationRecord> {
        let rows = sqlx::query(
            r#"
            SELECT s.*, u.username
            FROM sanctions s
            JOIN users u ON u.id = s.moderator_id
            WHERE s.user_id = $1
            ORDER BY s.created_at DESC
            "#
        )
        .bind(user_id)
        .fetch_all(&self.hub.db)
        .await
        .map_err(|e| ChatError::from_sqlx_error("database_operation", e))?;

        let mut sanctions = Vec::new();
        let mut warning_count = 0;
        let mut mute_count = 0;
        let mut ban_count = 0;
        let mut is_currently_banned = false;
        let mut is_currently_muted = false;

        for row in rows {
            let sanction_type_str: String = row.get("sanction_type");
            let sanction_type: SanctionType = serde_json::from_str(&sanction_type_str)
                .map_err(|e| ChatError::from_json_error(e))?;

            let reason_str: String = row.get("reason");
            let reason: SanctionReason = serde_json::from_str(&reason_str)
                .map_err(|e| ChatError::from_json_error(e))?;

            let is_active: bool = row.get("is_active");
            
            // Compter les types de sanctions
            match sanction_type {
                SanctionType::Warning => warning_count += 1,
                SanctionType::Mute => {
                    mute_count += 1;
                    if is_active {
                        is_currently_muted = true;
                    }
                },
                SanctionType::TempBan | SanctionType::PermaBan => {
                    ban_count += 1;
                    if is_active {
                        is_currently_banned = true;
                    }
                },
                _ => {}
            }

            sanctions.push(Sanction {
                id: row.get("id"),
                user_id: row.get("user_id"),
                moderator_id: row.get("moderator_id"),
                sanction_type,
                reason,
                message: row.get("message"),
                duration: None, // Simplifié pour cet exemple
                created_at: row.get("created_at"),
                expires_at: row.get("expires_at"),
                is_active,
            });
        }

        // Calculer un score de réputation basique
        let reputation_score = 100 - (warning_count as i32 * 5) - (mute_count as i32 * 15) - (ban_count as i32 * 50);

        // Obtenir le nom d'utilisateur
        let username = self.get_username(user_id).await?;

        Ok(UserModerationRecord {
            user_id,
            username,
            sanctions,
            total_warnings: warning_count,
            total_mutes: mute_count,
            total_bans: ban_count,
            reputation_score,
            is_currently_banned,
            is_currently_muted,
        })
    }

    /// Détection de spam basique
    async fn detect_spam(&self, user_id: i32, content: &str) -> Result<bool> {
        // Vérifier les messages répétitifs
        let recent_messages = sqlx::query(
            "SELECT content FROM messages WHERE user_id = $1 AND created_at > NOW() - INTERVAL '5 minutes' ORDER BY created_at DESC LIMIT 5"
        )
        .bind(user_id)
        .fetch_all(&self.hub.db)
        .await
        .map_err(|e| ChatError::from_sqlx_error("database_operation", e))?;

        let similar_count = recent_messages.iter()
            .filter(|row| {
                let msg_content: String = row.get("content");
                self.calculate_similarity(content, &msg_content) > 0.8
            })
            .count();

        Ok(similar_count >= 3)
    }



    /// Calcule la similarité entre deux strings (simplifiée)
    fn calculate_similarity(&self, a: &str, b: &str) -> f32 {
        if a == b {
            return 1.0;
        }
        
        let a_len = a.len() as f32;
        let b_len = b.len() as f32;
        let max_len = a_len.max(b_len);
        
        if max_len == 0.0 {
            return 1.0;
        }
        
        // Distance de Levenshtein simplifiée
        let common_chars = a.chars().filter(|c| b.contains(*c)).count() as f32;
        common_chars / max_len
    }

    /// Détermine la sanction automatique appropriée
    async fn determine_auto_sanction(&self, user_record: &UserModerationRecord) -> Result<Option<SanctionType>> {
        match user_record.total_warnings {
            0 => Ok(Some(SanctionType::Warning)),
            1..=2 => Ok(Some(SanctionType::Mute)),
            _ => Ok(Some(SanctionType::TempBan)),
        }
    }

    /// Implémentations helpers simplifiées
    fn check_moderator_permissions(&self, role: &Role, sanction: &SanctionType) -> Result<()> {
        match sanction {
            SanctionType::Warning | SanctionType::Mute => {
                if matches!(role, Role::Admin | Role::Moderator) {
                    Ok(())
                } else {
                    Err(ChatError::unauthorized_simple("unauthorized_action"))
                }
            },
            SanctionType::Kick | SanctionType::TempBan => {
                if matches!(role, Role::Admin | Role::Moderator) {
                    Ok(())
                } else {
                    Err(ChatError::unauthorized_simple("unauthorized_action"))
                }
            },
            SanctionType::PermaBan => {
                if matches!(role, Role::Admin) {
                    Ok(())
                } else {
                    Err(ChatError::unauthorized_simple("unauthorized_action"))
                }
            },
        }
    }

    async fn user_exists(&self, user_id: i32) -> Result<bool> {
        let row = sqlx::query("SELECT EXISTS(SELECT 1 FROM users WHERE id = $1)")
            .bind(user_id)
            .fetch_one(&self.hub.db)
            .await
            .map_err(|e| ChatError::from_sqlx_error("database_operation", e))?;
        Ok(row.get(0))
    }

    async fn get_username(&self, user_id: i32) -> Result<String> {
        let row = sqlx::query("SELECT username FROM users WHERE id = $1")
            .bind(user_id)
            .fetch_one(&self.hub.db)
            .await
            .map_err(|e| ChatError::from_sqlx_error("database_operation", e))?;
        Ok(row.get(0))
    }

    async fn insert_sanction(
        &self,
        user_id: i32,
        moderator_id: i32,
        sanction_type: &SanctionType,
        reason: &SanctionReason,
        message: Option<&str>,
        expires_at: Option<chrono::DateTime<chrono::Utc>>,
    ) -> Result<i32> {
        let row = sqlx::query(
            "INSERT INTO sanctions (user_id, moderator_id, sanction_type, reason, message, expires_at) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id"
        )
        .bind(user_id)
        .bind(moderator_id)
        .bind(serde_json::to_string(sanction_type).map_err(|e| ChatError::from_json_error(e))?)
        .bind(serde_json::to_string(reason).map_err(|e| ChatError::from_json_error(e))?)
        .bind(message)
        .bind(expires_at)
        .fetch_one(&self.hub.db)
        .await
        .map_err(|e| ChatError::from_sqlx_error("database_operation", e))?;
        
        Ok(row.get(0))
    }

    async fn enforce_sanction(&self, user_id: i32, sanction_type: &SanctionType, _duration: Option<Duration>) -> Result<()> {
        // Ici on appliquerait les effets réels (déconnecter, bloquer messages, etc.)
        tracing::info!(user_id = %user_id, sanction_type = ?sanction_type, "⚖️ Sanction appliquée");
        Ok(())
    }

    async fn remove_sanction_effects(&self, user_id: i32, sanction_type: &SanctionType) -> Result<()> {
        // Ici on retirerait les effets (débloquer, etc.)
        tracing::info!(user_id = %user_id, sanction_type = ?sanction_type, "✅ Effets de sanction retirés");
        Ok(())
    }

    async fn notify_user_sanctioned(&self, user_id: i32, sanction_type: &SanctionType, _reason: &SanctionReason, _message: Option<&str>) -> Result<()> {
        // Ici on notifierait l'utilisateur
        tracing::info!(user_id = %user_id, sanction_type = ?sanction_type, "📢 Utilisateur notifié de la sanction");
        Ok(())
    }
} 