//! Common traits for Veza Rust services
//! 
//! This module defines shared traits that can be implemented by different
//! services to provide a consistent interface and enable easy testing.

use async_trait::async_trait;
use std::collections::HashMap;
use uuid::Uuid;

use crate::{VezaError, VezaResult};

/// Authentication provider trait
#[async_trait]
pub trait AuthProvider: Send + Sync {
    /// Validate a JWT token
    async fn validate_token(&self, token: &str) -> VezaResult<AuthClaims>;
    
    /// Generate a new JWT token
    async fn generate_token(&self, claims: &AuthClaims) -> VezaResult<String>;
    
    /// Refresh a token
    async fn refresh_token(&self, refresh_token: &str) -> VezaResult<AuthResult>;
    
    /// Revoke a token
    async fn revoke_token(&self, token: &str) -> VezaResult<()>;
    
    /// Check if a user has permission for a resource
    async fn check_permission(&self, user_id: Uuid, resource: &str, action: &str) -> VezaResult<bool>;
}

/// Message store trait for chat functionality
#[async_trait]
pub trait MessageStore: Send + Sync {
    /// Store a message
    async fn store_message(&self, message: &Message) -> VezaResult<()>;
    
    /// Get messages for a conversation
    async fn get_messages(&self, conversation_id: Uuid, limit: u32, offset: u32) -> VezaResult<Vec<Message>>;
    
    /// Get a specific message
    async fn get_message(&self, message_id: Uuid) -> VezaResult<Option<Message>>;
    
    /// Update a message
    async fn update_message(&self, message_id: Uuid, content: &str) -> VezaResult<()>;
    
    /// Delete a message
    async fn delete_message(&self, message_id: Uuid) -> VezaResult<()>;
    
    /// Mark messages as read
    async fn mark_as_read(&self, user_id: Uuid, conversation_id: Uuid, message_id: Uuid) -> VezaResult<()>;
    
    /// Get unread count for a user
    async fn get_unread_count(&self, user_id: Uuid) -> VezaResult<u32>;
}

/// Stream provider trait for audio streaming
#[async_trait]
pub trait StreamProvider: Send + Sync {
    /// Get stream URL for a track
    async fn get_stream_url(&self, track_id: Uuid, user_id: Uuid) -> VezaResult<String>;
    
    /// Validate stream access
    async fn validate_access(&self, track_id: Uuid, user_id: Uuid) -> VezaResult<bool>;
    
    /// Get track metadata
    async fn get_track_metadata(&self, track_id: Uuid) -> VezaResult<TrackMetadata>;
    
    /// Get audio chunk
    async fn get_audio_chunk(&self, track_id: Uuid, chunk_index: u32) -> VezaResult<Vec<u8>>;
    
    /// Get playlist
    async fn get_playlist(&self, playlist_id: Uuid, user_id: Uuid) -> VezaResult<Playlist>;
    
    /// Create playlist
    async fn create_playlist(&self, user_id: Uuid, name: &str, tracks: Vec<Uuid>) -> VezaResult<Playlist>;
}

/// Cache provider trait
#[async_trait]
pub trait CacheProvider: Send + Sync {
    /// Get a value from cache
    async fn get<T>(&self, key: &str) -> VezaResult<Option<T>>
    where
        T: serde::de::DeserializeOwned;
    
    /// Set a value in cache
    async fn set<T>(&self, key: &str, value: &T, ttl: Option<u64>) -> VezaResult<()>
    where
        T: serde::Serialize;
    
    /// Delete a value from cache
    async fn delete(&self, key: &str) -> VezaResult<()>;
    
    /// Check if a key exists
    async fn exists(&self, key: &str) -> VezaResult<bool>;
    
    /// Get multiple values
    async fn get_many<T>(&self, keys: &[String]) -> VezaResult<HashMap<String, T>>
    where
        T: serde::de::DeserializeOwned;
    
    /// Set multiple values
    async fn set_many<T>(&self, values: HashMap<String, T>, ttl: Option<u64>) -> VezaResult<()>
    where
        T: serde::Serialize;
    
    /// Clear cache
    async fn clear(&self) -> VezaResult<()>;
    
    /// Get cache statistics
    async fn stats(&self) -> VezaResult<CacheStats>;
}

/// Database provider trait
#[async_trait]
pub trait DatabaseProvider: Send + Sync {
    /// Execute a query
    async fn execute(&self, query: &str, params: &[serde_json::Value]) -> VezaResult<u64>;
    
    /// Query a single row
    async fn query_one<T>(&self, query: &str, params: &[serde_json::Value]) -> VezaResult<Option<T>>
    where
        T: serde::de::DeserializeOwned;
    
    /// Query multiple rows
    async fn query_many<T>(&self, query: &str, params: &[serde_json::Value]) -> VezaResult<Vec<T>>
    where
        T: serde::de::DeserializeOwned;
    
    /// Begin a transaction
    /// Note: This returns a type-erased transaction provider
    /// Implementations should return their concrete transaction type
    async fn begin_transaction(&self) -> VezaResult<()>;
    
    /// Health check
    async fn health_check(&self) -> VezaResult<()>;
}

/// Transaction provider trait
#[async_trait]
pub trait TransactionProvider: Send + Sync {
    /// Execute a query in transaction
    async fn execute(&self, query: &str, params: &[serde_json::Value]) -> VezaResult<u64>;
    
    /// Query a single row in transaction
    async fn query_one<T>(&self, query: &str, params: &[serde_json::Value]) -> VezaResult<Option<T>>
    where
        T: serde::de::DeserializeOwned;
    
    /// Query multiple rows in transaction
    async fn query_many<T>(&self, query: &str, params: &[serde_json::Value]) -> VezaResult<Vec<T>>
    where
        T: serde::de::DeserializeOwned;
    
    /// Commit transaction
    async fn commit(self: Box<Self>) -> VezaResult<()>;
    
    /// Rollback transaction
    async fn rollback(self: Box<Self>) -> VezaResult<()>;
}

/// Rate limiter trait
#[async_trait]
pub trait RateLimiter: Send + Sync {
    /// Check if a request is allowed
    async fn is_allowed(&self, key: &str, limit: u32, window: u64) -> VezaResult<bool>;
    
    /// Get remaining requests
    async fn get_remaining(&self, key: &str, limit: u32, window: u64) -> VezaResult<u32>;
    
    /// Reset rate limit for a key
    async fn reset(&self, key: &str) -> VezaResult<()>;
    
    /// Get rate limit info
    async fn get_info(&self, key: &str, limit: u32, window: u64) -> VezaResult<RateLimitInfo>;
}

/// Metrics provider trait
#[async_trait]
pub trait MetricsProvider: Send + Sync {
    /// Increment a counter
    async fn increment_counter(&self, name: &str, labels: &[(&str, &str)]) -> VezaResult<()>;
    
    /// Increment a counter by a value
    async fn increment_counter_by(&self, name: &str, value: f64, labels: &[(&str, &str)]) -> VezaResult<()>;
    
    /// Set a gauge value
    async fn set_gauge(&self, name: &str, value: f64, labels: &[(&str, &str)]) -> VezaResult<()>;
    
    /// Observe a histogram value
    async fn observe_histogram(&self, name: &str, value: f64, labels: &[(&str, &str)]) -> VezaResult<()>;
    
    /// Observe a summary value
    async fn observe_summary(&self, name: &str, value: f64, labels: &[(&str, &str)]) -> VezaResult<()>;
    
    /// Get metrics as string
    async fn get_metrics(&self) -> VezaResult<String>;
}

/// Logger trait
pub trait Logger: Send + Sync {
    /// Log a trace message
    fn trace(&self, message: &str, fields: &[(&str, String)]);
    
    /// Log a debug message
    fn debug(&self, message: &str, fields: &[(&str, String)]);
    
    /// Log an info message
    fn info(&self, message: &str, fields: &[(&str, String)]);
    
    /// Log a warning message
    fn warn(&self, message: &str, fields: &[(&str, String)]);
    
    /// Log an error message
    fn error(&self, message: &str, fields: &[(&str, String)]);
    
    /// Create a child logger with additional fields
    fn child(&self, fields: &[(&str, String)]) -> Box<dyn Logger>;
}

/// WebSocket handler trait
#[async_trait]
pub trait WebSocketHandler: Send + Sync {
    /// Handle a new connection
    async fn handle_connect(&self, user_id: Uuid, connection_id: Uuid) -> VezaResult<()>;
    
    /// Handle a message
    async fn handle_message(&self, user_id: Uuid, connection_id: Uuid, message: &str) -> VezaResult<()>;
    
    /// Handle a disconnection
    async fn handle_disconnect(&self, user_id: Uuid, connection_id: Uuid) -> VezaResult<()>;
    
    /// Broadcast a message to all users in a conversation
    async fn broadcast_to_conversation(&self, conversation_id: Uuid, message: &str, exclude_user: Option<Uuid>) -> VezaResult<()>;
    
    /// Send a message to a specific user
    async fn send_to_user(&self, user_id: Uuid, message: &str) -> VezaResult<()>;
}

/// File storage trait
#[async_trait]
pub trait FileStorage: Send + Sync {
    /// Store a file
    async fn store_file(&self, path: &str, content: &[u8]) -> VezaResult<String>;
    
    /// Get a file
    async fn get_file(&self, path: &str) -> VezaResult<Vec<u8>>;
    
    /// Delete a file
    async fn delete_file(&self, path: &str) -> VezaResult<()>;
    
    /// Check if a file exists
    async fn file_exists(&self, path: &str) -> VezaResult<bool>;
    
    /// Get file metadata
    async fn get_file_metadata(&self, path: &str) -> VezaResult<FileMetadata>;
    
    /// List files in a directory
    async fn list_files(&self, path: &str) -> VezaResult<Vec<String>>;
}

/// Notification service trait
#[async_trait]
pub trait NotificationService: Send + Sync {
    /// Send a push notification
    async fn send_push_notification(&self, user_id: Uuid, title: &str, body: &str, data: &HashMap<String, String>) -> VezaResult<()>;
    
    /// Send an in-app notification
    async fn send_in_app_notification(&self, user_id: Uuid, message: &str, data: &HashMap<String, serde_json::Value>) -> VezaResult<()>;
    
    /// Send an email
    async fn send_email(&self, to: &str, subject: &str, body: &str) -> VezaResult<()>;
    
    /// Send an SMS
    async fn send_sms(&self, to: &str, message: &str) -> VezaResult<()>;
}

/// Health check trait
#[async_trait]
pub trait HealthCheck: Send + Sync {
    /// Check if the service is healthy
    async fn is_healthy(&self) -> VezaResult<bool>;
    
    /// Get detailed health information
    async fn get_health_info(&self) -> VezaResult<HealthInfo>;
    
    /// Get service name
    fn service_name(&self) -> &str;
    
    /// Get service version
    fn service_version(&self) -> &str;
}

// Data types used by traits

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct AuthClaims {
    pub user_id: Uuid,
    pub username: String,
    pub email: String,
    pub roles: Vec<String>,
    pub exp: u64,
    pub iat: u64,
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct AuthResult {
    pub access_token: String,
    pub refresh_token: String,
    pub expires_in: u64,
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct Message {
    pub id: Uuid,
    pub conversation_id: Uuid,
    pub user_id: Uuid,
    pub content: String,
    pub message_type: String,
    pub created_at: chrono::DateTime<chrono::Utc>,
    pub updated_at: chrono::DateTime<chrono::Utc>,
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct TrackMetadata {
    pub id: Uuid,
    pub title: String,
    pub artist: String,
    pub album: String,
    pub duration: u32,
    pub file_size: u64,
    pub format: String,
    pub bitrate: u32,
    pub sample_rate: u32,
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct Playlist {
    pub id: Uuid,
    pub name: String,
    pub user_id: Uuid,
    pub tracks: Vec<Uuid>,
    pub created_at: chrono::DateTime<chrono::Utc>,
    pub updated_at: chrono::DateTime<chrono::Utc>,
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct CacheStats {
    pub hits: u64,
    pub misses: u64,
    pub keys: u64,
    pub memory_usage: u64,
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct RateLimitInfo {
    pub limit: u32,
    pub remaining: u32,
    pub reset_time: u64,
    pub retry_after: Option<u64>,
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct FileMetadata {
    pub path: String,
    pub size: u64,
    pub mime_type: String,
    pub created_at: chrono::DateTime<chrono::Utc>,
    pub modified_at: chrono::DateTime<chrono::Utc>,
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct HealthInfo {
    pub status: String,
    pub version: String,
    pub uptime: u64,
    pub dependencies: HashMap<String, String>,
    pub metrics: HashMap<String, serde_json::Value>,
}
