//! Client gRPC pour communiquer avec veza-backend-api

use crate::error::{ChatError, Result};
use serde::{Deserialize, Serialize};
use std::time::Duration;
use tokio::time::timeout;
use tracing::{info, warn, error};

/// Configuration du client gRPC
#[derive(Debug, Clone)]
pub struct GrpcClientConfig {
    pub backend_api_url: String,
    pub timeout_seconds: u64,
    pub max_retries: u32,
}

impl Default for GrpcClientConfig {
    fn default() -> Self {
        Self {
            backend_api_url: std::env::var("BACKEND_API_URL")
                .unwrap_or_else(|_| "http://localhost:8080".to_string()),
            timeout_seconds: 30,
            max_retries: 3,
        }
    }
}

/// Informations utilisateur depuis le backend
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UserInfo {
    pub id: i64,
    pub username: String,
    pub email: String,
    pub role: String,
    pub is_active: bool,
}

/// Informations de session utilisateur
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SessionInfo {
    pub user_id: i64,
    pub session_token: String,
    pub expires_at: String,
    pub is_active: bool,
}

/// Client gRPC pour communiquer avec le backend API
pub struct BackendApiClient {
    config: GrpcClientConfig,
    http_client: reqwest::Client,
}

impl BackendApiClient {
    /// Crée un nouveau client
    pub fn new(config: GrpcClientConfig) -> Self {
        let http_client = reqwest::Client::builder()
            .timeout(Duration::from_secs(config.timeout_seconds))
            .build()
            .unwrap_or_default();

        Self {
            config,
            http_client,
        }
    }

    /// Crée un client avec la configuration par défaut
    pub fn with_default_config() -> Self {
        Self::new(GrpcClientConfig::default())
    }

    /// Vérifie la validité d'un token JWT
    pub async fn verify_jwt_token(&self, token: &str) -> Result<UserInfo> {
        info!("🔍 Vérification du token JWT avec le backend API");

        let url = format!("{}/api/v1/auth/profile", self.config.backend_api_url);
        
        let response = timeout(
            Duration::from_secs(self.config.timeout_seconds),
            self.http_client
                .get(&url)
                .header("Authorization", format!("Bearer {}", token))
                .send()
        ).await
        .map_err(|_| ChatError::configuration_error("Timeout lors de la vérification du token"))?
        .map_err(|e| ChatError::configuration_error(&format!("Erreur HTTP: {}", e)))?;

        if response.status().is_success() {
            let response_body: serde_json::Value = response.json().await
                .map_err(|e| ChatError::configuration_error(&format!("Erreur parsing JSON: {}", e)))?;

            // Parser la réponse du backend
            if let Some(data) = response_body.get("data") {
                if let Some(user_data) = data.get("user") {
                    let user_info = UserInfo {
                        id: user_data.get("id").and_then(|v| v.as_i64()).unwrap_or(0),
                        username: user_data.get("username").and_then(|v| v.as_str()).unwrap_or("unknown").to_string(),
                        email: user_data.get("email").and_then(|v| v.as_str()).unwrap_or("").to_string(),
                        role: user_data.get("role").and_then(|v| v.as_str()).unwrap_or("user").to_string(),
                        is_active: user_data.get("is_active").and_then(|v| v.as_bool()).unwrap_or(false),
                    };

                    info!("✅ Token valide pour l'utilisateur: {}", user_info.username);
                    return Ok(user_info);
                }
            }

            error!("❌ Réponse invalide du backend API");
            Err(ChatError::configuration_error("Réponse invalide du backend API"))
        } else if response.status() == 401 {
            warn!("⚠️ Token JWT invalide ou expiré");
            Err(ChatError::configuration_error("Token JWT invalide ou expiré"))
        } else {
            error!("❌ Erreur backend API: {}", response.status());
            Err(ChatError::configuration_error(&format!("Erreur backend API: {}", response.status())))
        }
    }

    /// Synchronise les informations utilisateur
    pub async fn sync_user_info(&self, user_id: i64) -> Result<UserInfo> {
        info!("🔄 Synchronisation des informations utilisateur ID: {}", user_id);

        let url = format!("{}/api/v1/users/{}", self.config.backend_api_url, user_id);
        
        let response = timeout(
            Duration::from_secs(self.config.timeout_seconds),
            self.http_client.get(&url).send()
        ).await
        .map_err(|_| ChatError::configuration_error("Timeout lors de la synchronisation utilisateur"))?
        .map_err(|e| ChatError::configuration_error(&format!("Erreur HTTP: {}", e)))?;

        if response.status().is_success() {
            let user_info: UserInfo = response.json().await
                .map_err(|e| ChatError::configuration_error(&format!("Erreur parsing user info: {}", e)))?;

            info!("✅ Informations utilisateur synchronisées: {}", user_info.username);
            Ok(user_info)
        } else {
            error!("❌ Impossible de récupérer les informations utilisateur: {}", response.status());
            Err(ChatError::configuration_error(&format!("Erreur récupération utilisateur: {}", response.status())))
        }
    }

    /// Notifie le backend d'un nouveau message de chat
    pub async fn notify_new_message(&self, message_id: i32, room_id: &str, sender_id: i64) -> Result<()> {
        info!("📢 Notification nouveau message au backend: message={}, room={}, sender={}", 
              message_id, room_id, sender_id);

        let url = format!("{}/api/v1/chat/message-notifications", self.config.backend_api_url);
        
        let payload = serde_json::json!({
            "message_id": message_id,
            "room_id": room_id,
            "sender_id": sender_id,
            "timestamp": chrono::Utc::now()
        });

        let response = timeout(
            Duration::from_secs(self.config.timeout_seconds),
            self.http_client
                .post(&url)
                .json(&payload)
                .send()
        ).await
        .map_err(|_| ChatError::configuration_error("Timeout lors de la notification"))?
        .map_err(|e| ChatError::configuration_error(&format!("Erreur HTTP notification: {}", e)))?;

        if response.status().is_success() {
            info!("✅ Notification envoyée avec succès");
            Ok(())
        } else {
            warn!("⚠️ Échec notification (non critique): {}", response.status());
            // Les notifications sont non-critiques, ne pas faire échouer l'opération
            Ok(())
        }
    }

    /// Vérifie la santé du backend API
    pub async fn health_check(&self) -> Result<bool> {
        let url = format!("{}/health", self.config.backend_api_url);
        
        match timeout(
            Duration::from_secs(5), // Timeout court pour les health checks
            self.http_client.get(&url).send()
        ).await {
            Ok(Ok(response)) => Ok(response.status().is_success()),
            _ => Ok(false),
        }
    }

    /// Met à jour les statistiques d'activité utilisateur
    pub async fn update_user_activity(&self, user_id: i64, activity_type: &str) -> Result<()> {
        let url = format!("{}/api/v1/users/{}/activity", self.config.backend_api_url, user_id);
        
        let payload = serde_json::json!({
            "activity_type": activity_type,
            "timestamp": chrono::Utc::now()
        });

        let response = timeout(
            Duration::from_secs(self.config.timeout_seconds),
            self.http_client
                .post(&url)
                .json(&payload)
                .send()
        ).await
        .map_err(|_| ChatError::configuration_error("Timeout lors de la mise à jour d'activité"))?
        .map_err(|e| ChatError::configuration_error(&format!("Erreur HTTP activité: {}", e)))?;

        if response.status().is_success() {
            info!("✅ Activité utilisateur mise à jour: {} - {}", user_id, activity_type);
            Ok(())
        } else {
            warn!("⚠️ Échec mise à jour activité (non critique): {}", response.status());
            // Les mises à jour d'activité sont non-critiques
            Ok(())
        }
    }
} 