//! # Gestion d'erreurs unifiée pour Veza Chat Server
//!
//! Ce module fournit un système d'erreurs cohérent et complet avec:
//! - Catégorisation des erreurs par domaine
//! - Codes d'erreur standardisés  
//! - Logging automatique selon la gravité
//! - Sérialisation pour l'API

use serde::{Deserialize, Serialize};
use std::fmt;
use thiserror::Error;

/// Type alias pour Result avec notre erreur personnalisée
pub type Result<T> = std::result::Result<T, ChatError>;

/// Erreurs principales du système de chat
#[derive(Error, Debug)]
pub enum ChatError {
    // ═══════════════════════════════════════════════════════════════════════
    // ERREURS D'AUTHENTIFICATION ET AUTORISATION
    // ═══════════════════════════════════════════════════════════════════════
    /// Token JWT invalide ou expiré
    #[error("Token d'authentification invalide: {reason}")]
    InvalidToken { reason: String },

    /// Utilisateur non autorisé pour cette action
    #[error("Accès refusé: {action}")]
    Unauthorized { action: String },

    /// Utilisateur banni ou suspendu
    #[error("Compte suspendu: {reason}")]
    AccountSuspended { reason: String },

    /// Tentative de connexion avec des identifiants invalides
    #[error("Identifiants invalides")]
    InvalidCredentials,

    /// Authentification à deux facteurs requise
    #[error("Authentification 2FA requise")]
    TwoFactorRequired,

    /// Code 2FA invalide
    #[error("Code d'authentification 2FA invalide")]
    InvalidTwoFactorCode,

    // ═══════════════════════════════════════════════════════════════════════
    // ERREURS DE VALIDATION ET CONTENU
    // ═══════════════════════════════════════════════════════════════════════
    /// Contenu de message trop long
    #[error("Message trop long: {actual} caractères (max: {max})")]
    MessageTooLong { actual: usize, max: usize },

    /// Contenu inapproprié détecté
    #[error("Contenu inapproprié détecté: {reason}")]
    InappropriateContent { reason: String },

    /// Spam détecté par les filtres
    #[error("Contenu identifié comme spam")]
    SpamDetected,

    /// Format de données invalide
    #[error("Format invalide pour {field}: {reason}")]
    InvalidFormat { field: String, reason: String },

    /// Paramètre requis manquant
    #[error("Paramètre requis manquant: {param}")]
    MissingParameter { param: String },

    /// Valeur hors limites acceptables
    #[error("{field} hors limites: {value} (min: {min}, max: {max})")]
    OutOfRange {
        field: String,
        value: i64,
        min: i64,
        max: i64,
    },

    // ═══════════════════════════════════════════════════════════════════════
    // ERREURS DE RATE LIMITING ET QUOTA
    // ═══════════════════════════════════════════════════════════════════════
    /// Limite de taux dépassée
    #[error("Limite de taux dépassée pour {action}: {current}/{limit} dans {window}s")]
    RateLimitExceeded {
        action: String,
        current: u32,
        limit: u32,
        window: u64,
    },

    /// Quota utilisateur dépassé
    #[error("Quota {quota_type} dépassé: {used}/{limit}")]
    QuotaExceeded {
        quota_type: String,
        used: u64,
        limit: u64,
    },

    /// Trop de connexions simultanées
    #[error("Trop de connexions simultanées: {current}/{max}")]
    TooManyConnections { current: u32, max: u32 },

    // ═══════════════════════════════════════════════════════════════════════
    // ERREURS RÉSEAU ET WEBSOCKET
    // ═══════════════════════════════════════════════════════════════════════
    /// Erreur de connexion WebSocket
    #[error("Erreur WebSocket: {source}")]
    WebSocket {
        #[source]
        source: tokio_tungstenite::tungstenite::Error,
    },

    /// Connexion fermée de manière inattendue
    #[error("Connexion fermée: {reason}")]
    ConnectionClosed { reason: String },

    /// Timeout de connexion
    #[error("Timeout de connexion après {seconds}s")]
    ConnectionTimeout { seconds: u64 },

    /// Erreur réseau générale
    #[error("Erreur réseau: {message}")]
    NetworkError { message: String },

    // ═══════════════════════════════════════════════════════════════════════
    // ERREURS DE BASE DE DONNÉES
    // ═══════════════════════════════════════════════════════════════════════
    /// Erreur de base de données
    #[error("Erreur base de données: {operation}")]
    Database {
        operation: String,
        #[source]
        source: sqlx::Error,
    },

    /// Ressource non trouvée
    #[error("{resource} non trouvé(e): {id}")]
    NotFound { resource: String, id: String },

    /// Conflit de données (ex: violation de contrainte unique)
    #[error("Conflit de données: {reason}")]
    Conflict { reason: String },

    /// Transaction échouée
    #[error("Transaction échouée: {reason}")]
    TransactionFailed { reason: String },

    // ═══════════════════════════════════════════════════════════════════════
    // ERREURS DE CONVERSATIONS ET MESSAGES
    // ═══════════════════════════════════════════════════════════════════════
    /// Conversation inexistante
    #[error("Conversation {id} inexistante")]
    ConversationNotFound { id: String },

    /// Utilisateur pas membre de la conversation
    #[error("Utilisateur non membre de la conversation {conversation_id}")]
    NotMember { conversation_id: String },

    /// Permissions insuffisantes dans la conversation
    #[error("Permissions insuffisantes pour {action} dans {conversation_id}")]
    InsufficientPermissions {
        action: String,
        conversation_id: String,
    },

    /// Conversation archivée
    #[error("Conversation {id} archivée")]
    ConversationArchived { id: String },

    /// Message non trouvé
    #[error("Message {id} non trouvé")]
    MessageNotFound { id: String },

    /// Impossible d'éditer le message
    #[error("Edition impossible: {reason}")]
    EditForbidden { reason: String },

    // ═══════════════════════════════════════════════════════════════════════
    // ERREURS DE FICHIERS ET UPLOAD
    // ═══════════════════════════════════════════════════════════════════════
    /// Fichier trop volumineux
    #[error("Fichier trop volumineux: {size} bytes (max: {max_size})")]
    FileTooLarge { size: u64, max_size: u64 },

    /// Type de fichier non autorisé
    #[error("Type de fichier non autorisé: {mime_type}")]
    UnsupportedFileType { mime_type: String },

    /// Fichier infecté détecté
    #[error("Fichier potentiellement dangereux détecté")]
    MaliciousFile,

    /// Erreur d'upload
    #[error("Erreur upload: {reason}")]
    UploadError { reason: String },

    // ═══════════════════════════════════════════════════════════════════════
    // ERREURS SYSTÈME ET CONFIGURATION
    // ═══════════════════════════════════════════════════════════════════════
    /// Erreur de configuration
    #[error("Erreur configuration: {message}")]
    Configuration { message: String },

    /// Service indisponible
    #[error("Service {service} indisponible: {reason}")]
    ServiceUnavailable { service: String, reason: String },

    /// Erreur de cache
    #[error("Erreur cache: {operation}")]
    Cache { operation: String },

    /// Timeout d'arrêt du serveur
    #[error("Timeout lors de l'arrêt du serveur")]
    ShutdownTimeout,

    /// Erreur interne non spécifiée
    #[error("Erreur interne: {message}")]
    Internal { message: String },

    /// EventBus RabbitMQ indisponible
    #[error("EventBus indisponible: {source}")]
    EventBusUnavailable {
        #[from]
        source: crate::event_bus::EventBusUnavailableError,
    },

    // ═══════════════════════════════════════════════════════════════════════
    // ERREURS DE PERMISSIONS ET RÉACTIONS
    // ═══════════════════════════════════════════════════════════════════════
    /// Permission refusée
    #[error("Permission refusée: {message}")]
    PermissionDenied { message: String },

    /// Réaction déjà existante
    #[error("Réaction déjà existante pour ce message")]
    ReactionAlreadyExists,

    /// Réaction non trouvée
    #[error("Réaction non trouvée")]
    ReactionNotFound,

    // ═══════════════════════════════════════════════════════════════════════
    // ERREURS DE SÉCURITÉ
    // ═══════════════════════════════════════════════════════════════════════
    /// Activité suspecte détectée
    #[error("Activité suspecte détectée: {reason}")]
    SuspiciousActivity { reason: String },

    /// IP bloquée
    #[error("Adresse IP {ip} bloquée: {reason}")]
    IpBlocked { ip: String, reason: String },

    /// Tentative d'injection détectée
    #[error("Tentative d'injection détectée")]
    InjectionAttempt,

    /// Validation de sécurité échouée
    #[error("Validation sécurité échouée: {check}")]
    SecurityValidationFailed { check: String },

    /// Erreur de sérialisation JSON
    #[error("Erreur JSON: {source}")]
    Json {
        #[source]
        source: serde_json::Error,
    },

    /// Erreur de sérialisation générale
    #[error("Erreur de sérialisation {operation}: {message}")]
    Serialization { operation: String, message: String },

    /// Fonctionnalité non disponible
    #[error("Fonctionnalité {feature} non disponible: {reason}")]
    FeatureNotAvailable { feature: String, reason: String },

    /// Erreur de validation
    #[error("Erreur de validation pour {field}: {reason}")]
    ValidationError { field: String, reason: String },

    /// Erreur de parsing
    #[error("Erreur de parsing: {reason}")]
    ParseError { reason: String },

    /// Limite de connexions atteinte
    #[error("Limite de connexions simultanées atteinte")]
    ConnectionLimitReached,
}

impl ChatError {
    /// Retourne le code d'erreur HTTP approprié
    pub fn http_status(&self) -> u16 {
        match self {
            // 400 Bad Request
            Self::InvalidFormat { .. }
            | Self::MissingParameter { .. }
            | Self::OutOfRange { .. }
            | Self::MessageTooLong { .. }
            | Self::FileTooLarge { .. }
            | Self::UnsupportedFileType { .. } => 400,

            // 401 Unauthorized
            Self::InvalidToken { .. }
            | Self::InvalidCredentials
            | Self::TwoFactorRequired
            | Self::InvalidTwoFactorCode => 401,

            // 403 Forbidden
            Self::Unauthorized { .. }
            | Self::AccountSuspended { .. }
            | Self::InsufficientPermissions { .. }
            | Self::EditForbidden { .. }
            | Self::IpBlocked { .. } => 403,

            // 404 Not Found
            Self::NotFound { .. }
            | Self::ConversationNotFound { .. }
            | Self::MessageNotFound { .. } => 404,

            // 409 Conflict
            Self::Conflict { .. } => 409,

            // 413 Payload Too Large

            // 422 Unprocessable Entity
            Self::InappropriateContent { .. } | Self::SpamDetected | Self::MaliciousFile => 422,

            // 429 Too Many Requests
            Self::RateLimitExceeded { .. }
            | Self::QuotaExceeded { .. }
            | Self::TooManyConnections { .. } => 429,

            // 500 Internal Server Error
            Self::Database { .. }
            | Self::Internal { .. }
            | Self::Configuration { .. }
            | Self::TransactionFailed { .. }
            | Self::UploadError { .. }
            | Self::Cache { .. } => 500,

            // 503 Service Unavailable
            Self::ServiceUnavailable { .. }
            | Self::ShutdownTimeout
            | Self::EventBusUnavailable { .. } => 503, // Added EventBusUnavailable

            // 418 I'm a teapot (pour les tentatives d'injection)
            Self::InjectionAttempt => 418,

            // Autres erreurs -> 500
            Self::Json { .. }
            | Self::Serialization { .. }
            | Self::FeatureNotAvailable { .. }
            | Self::ConnectionLimitReached
            | Self::SecurityValidationFailed { .. }
            | Self::SuspiciousActivity { .. }
            | Self::ConversationArchived { .. }
            | Self::NetworkError { .. }
            | Self::ConnectionClosed { .. }
            | Self::ConnectionTimeout { .. }
            | Self::WebSocket { .. }
            | Self::NotMember { .. } => 500,

            // Nouvelles erreurs
            Self::PermissionDenied { .. } => 403,
            Self::ReactionAlreadyExists => 409,
            Self::ReactionNotFound => 404,
            Self::ValidationError { .. } => 400,
            Self::ParseError { .. } => 400,
        }
    }

    /// Retourne la sévérité de l'erreur pour les logs
    pub fn severity(&self) -> ErrorSeverity {
        match self {
            // CRITICAL - Erreur système critique
            Self::Database { .. }
            | Self::ServiceUnavailable { .. }
            | Self::ShutdownTimeout
            | Self::SuspiciousActivity { .. }
            | Self::InjectionAttempt
            | Self::IpBlocked { .. }
            | Self::EventBusUnavailable { .. } => ErrorSeverity::High, // Added EventBusUnavailable
            // HIGH - Problème sérieux à traiter rapidement
            Self::InvalidToken { .. }
            | Self::AccountSuspended { .. }
            | Self::InvalidFormat { .. }
            | Self::MissingParameter { .. }
            | Self::OutOfRange { .. }
            | Self::MessageTooLong { .. }
            | Self::FileTooLarge { .. }
            | Self::UnsupportedFileType { .. }
            | Self::TransactionFailed { .. }
            | Self::UploadError { .. }
            | Self::InvalidCredentials
            | Self::InvalidTwoFactorCode
            | Self::InappropriateContent { .. }
            | Self::SpamDetected
            | Self::MaliciousFile
            | Self::ConversationNotFound { .. }
            | Self::InsufficientPermissions { .. }
            | Self::MessageNotFound { .. }
            | Self::EditForbidden { .. }
            | Self::Conflict { .. }
            | Self::ConnectionLimitReached
            | Self::SecurityValidationFailed { .. } => ErrorSeverity::Medium,

            // Gravité moyenne - Erreurs qui affectent l'utilisateur
            Self::RateLimitExceeded { .. }
            | Self::QuotaExceeded { .. }
            | Self::TooManyConnections { .. }
            | Self::Unauthorized { .. }
            | Self::NotFound { .. } => ErrorSeverity::Low,

            // INFO - Information
            Self::ConnectionClosed { .. }
            | Self::TwoFactorRequired
            | Self::NotMember { .. }
            | Self::Json { .. }
            | Self::Serialization { .. }
            | Self::FeatureNotAvailable { .. }
            | Self::ConversationArchived { .. }
            | Self::WebSocket { .. }
            | Self::NetworkError { .. }
            | Self::ConnectionTimeout { .. }
            | Self::Cache { .. }
            | Self::Internal { .. }
            | Self::Configuration { .. } => ErrorSeverity::Info,

            // Nouvelles erreurs
            Self::PermissionDenied { .. } => ErrorSeverity::Warning,
            Self::ReactionAlreadyExists => ErrorSeverity::Info,
            Self::ReactionNotFound => ErrorSeverity::Info,
            Self::ValidationError { .. } => ErrorSeverity::Low,
            Self::ParseError { .. } => ErrorSeverity::Low,
        }
    }

    /// Retourne un message d'erreur sécurisé pour le client
    pub fn public_message(&self) -> String {
        match self {
            // Messages détaillés OK pour le client
            Self::InvalidFormat { field, .. } => format!("Format invalide pour {}", field),
            Self::MissingParameter { param } => format!("Paramètre manquant: {}", param),
            Self::MessageTooLong { max, .. } => {
                format!("Message trop long (max: {} caractères)", max)
            }
            Self::RateLimitExceeded { action, window, .. } => {
                format!(
                    "Trop de requêtes pour {}, veuillez patienter {}s",
                    action, window
                )
            }

            // Messages génériques pour éviter la divulgation d'informations
            Self::Database { .. } => "Erreur temporaire, veuillez réessayer".to_string(),
            Self::Internal { .. } => "Erreur interne du serveur".to_string(),
            Self::Configuration { .. } => "Service temporairement indisponible".to_string(),
            Self::InjectionAttempt => "Requête rejetée".to_string(),
            Self::SuspiciousActivity { .. } => "Activité inhabituelle détectée".to_string(),

            // Message par défaut
            _ => self.to_string(),
        }
    }

    /// Crée une erreur de base de données avec contexte
    pub fn database_error(operation: &str, source: sqlx::Error) -> Self {
        Self::Database {
            operation: operation.to_string(),
            source,
        }
    }

    /// Crée une erreur d'autorisation avec contexte
    pub fn unauthorized(action: &str) -> Self {
        Self::Unauthorized {
            action: action.to_string(),
        }
    }

    /// Crée une erreur de ressource non trouvée
    pub fn not_found(resource: &str, id: &str) -> Self {
        Self::NotFound {
            resource: resource.to_string(),
            id: id.to_string(),
        }
    }

    /// Helper pour les erreurs de configuration
    pub fn configuration_error(message: &str) -> Self {
        Self::Configuration {
            message: message.to_string(),
        }
    }

    /// Helper pour les erreurs de message trop long
    pub fn message_too_long(actual: usize, max: usize) -> Self {
        Self::MessageTooLong { actual, max }
    }

    /// Helper pour les erreurs de sérialisation
    pub fn serialization_error(type_name: &str, _data: &str, source: serde_json::Error) -> Self {
        Self::Serialization {
            operation: format!("serialize {}", type_name),
            message: source.to_string(),
        }
    }

    /// Helper pour les erreurs WebSocket
    pub fn websocket_error(
        _operation: &str,
        source: tokio_tungstenite::tungstenite::Error,
    ) -> Self {
        Self::WebSocket { source }
    }

    /// Helper pour les fonctionnalités non disponibles
    pub fn feature_not_available(feature: &str, reason: &str) -> Self {
        Self::FeatureNotAvailable {
            feature: feature.to_string(),
            reason: reason.to_string(),
        }
    }

    /// Helper pour convertir sqlx::Error avec une meilleure gestion
    pub fn from_sqlx_error(operation: &str, error: sqlx::Error) -> Self {
        Self::Database {
            operation: operation.to_string(),
            source: error,
        }
    }

    /// Helper pour les erreurs JSON
    pub fn from_json_error(error: serde_json::Error) -> Self {
        Self::Json { source: error }
    }

    /// Helper pour les erreurs de rate limiting avec des valeurs par défaut
    pub fn rate_limit_exceeded_simple(action: &str) -> Self {
        Self::RateLimitExceeded {
            action: action.to_string(),
            current: 0,
            limit: 0,
            window: 60,
        }
    }

    /// Helper pour les erreurs d'autorisation
    pub fn unauthorized_simple(action: &str) -> Self {
        Self::Unauthorized {
            action: action.to_string(),
        }
    }

    /// Helper pour les erreurs de contenu inapproprié
    pub fn inappropriate_content_simple(reason: &str) -> Self {
        Self::InappropriateContent {
            reason: reason.to_string(),
        }
    }

    /// Helper pour les erreurs de validation
    pub fn validation_error(reason: &str) -> Self {
        Self::ValidationError {
            field: "general".to_string(),
            reason: reason.to_string(),
        }
    }

    /// Helper pour les erreurs de permission
    pub fn permission_denied(message: &str) -> Self {
        Self::PermissionDenied {
            message: message.to_string(),
        }
    }

    /// Helper pour les erreurs internes
    pub fn internal_error(message: String) -> Self {
        // Changed to String
        Self::Internal {
            message, // Direct assignment
        }
    }

    /// Helper pour les erreurs not found avec un seul paramètre
    pub fn not_found_simple(message: &str) -> Self {
        Self::NotFound {
            resource: "resource".to_string(),
            id: message.to_string(),
        }
    }
}

/// Niveaux de sévérité des erreurs
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ErrorSeverity {
    Info,
    Low,
    Medium,
    High,
    Critical,
    Warning,
}

impl fmt::Display for ErrorSeverity {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Info => write!(f, "INFO"),
            Self::Low => write!(f, "LOW"),
            Self::Medium => write!(f, "MEDIUM"),
            Self::High => write!(f, "HIGH"),
            Self::Critical => write!(f, "CRITICAL"),
            Self::Warning => write!(f, "WARNING"),
        }
    }
}

/// Implémentations de conversion depuis des erreurs externes
impl From<sqlx::Error> for ChatError {
    fn from(err: sqlx::Error) -> Self {
        Self::database_error("query", err)
    }
}

impl From<tokio_tungstenite::tungstenite::Error> for ChatError {
    fn from(err: tokio_tungstenite::tungstenite::Error) -> Self {
        Self::WebSocket { source: err }
    }
}

impl From<serde_json::Error> for ChatError {
    fn from(err: serde_json::Error) -> Self {
        Self::InvalidFormat {
            field: "json".to_string(),
            reason: err.to_string(),
        }
    }
}

impl From<std::env::VarError> for ChatError {
    fn from(err: std::env::VarError) -> Self {
        Self::Configuration {
            message: format!("Variable d'environnement manquante: {}", err),
        }
    }
}

/// Macro pour simplifier la création d'erreurs
#[macro_export]
macro_rules! chat_error {
    ($variant:ident, $($field:ident = $value:expr),*) => {
        $crate::error::ChatError::$variant {
            $($field: $value.into()),*
        }
    };
    ($variant:ident) => {
        $crate::error::ChatError::$variant
    };
}

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

    #[test]
    fn test_error_http_status() {
        assert_eq!(ChatError::InvalidCredentials.http_status(), 401);
        assert_eq!(ChatError::not_found("user", "123").http_status(), 404);
        assert_eq!(ChatError::unauthorized("send_message").http_status(), 403);
    }

    #[test]
    fn test_error_severity() {
        assert_eq!(ChatError::InjectionAttempt.severity(), ErrorSeverity::High);
        assert_eq!(
            ChatError::InvalidCredentials.severity(),
            ErrorSeverity::Medium
        );
        assert_eq!(ChatError::SpamDetected.severity(), ErrorSeverity::Medium);
    }

    #[test]
    fn test_public_message() {
        let error = ChatError::InvalidFormat {
            field: "email".to_string(),
            reason: "invalid format".to_string(),
        };
        assert_eq!(error.public_message(), "Format invalide pour email");

        let db_error = ChatError::database_error("insert", sqlx::Error::RowNotFound);
        assert_eq!(
            db_error.public_message(),
            "Erreur temporaire, veuillez réessayer"
        );
    }

    #[test]
    fn test_error_creation_helpers() {
        let error = ChatError::not_found("conversation", "room_123");
        match error {
            ChatError::NotFound { resource, id } => {
                assert_eq!(resource, "conversation");
                assert_eq!(id, "room_123");
            }
            _ => panic!("Wrong error type"),
        }
    }

    #[test]
    fn test_macro() {
        let error = chat_error!(MessageTooLong, actual = 5000_usize, max = 4000_usize);
        match error {
            ChatError::MessageTooLong { actual, max } => {
                assert_eq!(actual, 5000);
                assert_eq!(max, 4000);
            }
            _ => panic!("Wrong error type"),
        }
    }
}
