//! Risk Data Repository
//!
//! Production-ready risk management data layer for high-frequency trading systems.
//! Provides repositories for `VaR` calculations, compliance logging, position limits,
//! and risk data models with `PostgreSQL` and Redis integration.

#![allow(missing_docs)] // Internal implementation details
// Allow pedantic lints for repository implementation
#![allow(clippy::missing_docs_in_private_items)]
#![allow(clippy::clone_on_ref_ptr)]
#![allow(clippy::str_to_string)]
#![deny(clippy::unwrap_used, clippy::expect_used)]

use std::sync::Arc;

pub mod compliance;
pub mod limits;
pub mod models;
pub mod var;

// Import the repository traits and implementations
use crate::compliance::{ComplianceRepository, ComplianceRepositoryImpl};
use crate::limits::{LimitsRepository, LimitsRepositoryImpl};
use crate::var::{VarRepository, VarRepositoryImpl};

/// Configuration for the risk data repository
#[derive(Debug, Clone)]
pub struct RiskDataConfig {
    /// `PostgreSQL` database URL
    pub database_url: String,
    /// Redis connection URL
    pub redis_url: String,
    /// Maximum database connections
    pub max_connections: u32,
    /// Connection timeout in seconds
    pub connection_timeout_secs: u64,
}

impl Default for RiskDataConfig {
    fn default() -> Self {
        Self {
            database_url: "postgresql://localhost/foxhunt".to_owned(),
            redis_url: "redis://localhost:6379".to_owned(),
            max_connections: 10,
            connection_timeout_secs: 30,
        }
    }
}

/// Main risk data repository facade providing access to all risk data operations
#[derive(Debug, Clone)]
pub struct RiskDataRepository {
    var_repo: Arc<dyn VarRepository>,
    compliance_repo: Arc<dyn ComplianceRepository>,
    limits_repo: Arc<dyn LimitsRepository>,
}

impl RiskDataRepository {
    /// Create a new risk data repository with the given configuration
    ///
    /// # Errors
    /// Returns error if the operation fails
    pub async fn new(config: RiskDataConfig) -> Result<Self, RiskDataError> {
        let pool = sqlx::postgres::PgPoolOptions::new()
            .max_connections(config.max_connections)
            .acquire_timeout(std::time::Duration::from_secs(
                config.connection_timeout_secs,
            ))
            .connect(&config.database_url)
            .await?;

        let redis_client = redis::Client::open(config.redis_url)?;
        let redis_conn = redis::aio::ConnectionManager::new(redis_client).await?;

        let var_repo = Arc::new(VarRepositoryImpl::new(pool.clone(), redis_conn.clone()));
        let compliance_repo = Arc::new(ComplianceRepositoryImpl::new(
            pool.clone(),
            redis_conn.clone(),
        ));
        let limits_repo = Arc::new(LimitsRepositoryImpl::new(pool.clone(), redis_conn));

        Ok(Self {
            var_repo,
            compliance_repo,
            limits_repo,
        })
    }

    /// Get `VaR` repository
    pub fn var(&self) -> Arc<dyn VarRepository> {
        Arc::clone(&self.var_repo)
    }

    /// Get compliance repository
    pub fn compliance(&self) -> Arc<dyn ComplianceRepository> {
        Arc::clone(&self.compliance_repo)
    }

    /// Get limits repository
    pub fn limits(&self) -> Arc<dyn LimitsRepository> {
        Arc::clone(&self.limits_repo)
    }
}

/// Common error types for risk data operations
#[derive(Debug, thiserror::Error)]
pub enum RiskDataError {
    /// Database connection or query error
    #[error("Database error: {0}")]
    Database(#[from] sqlx::Error),

    /// Redis cache operation error
    #[error("Redis error: {0}")]
    Redis(#[from] redis::RedisError),

    /// JSON serialization/deserialization error
    #[error("Serialization error: {0}")]
    Serialization(#[from] serde_json::Error),

    /// `VaR` calculation or modeling error
    #[error("VaR calculation error: {0}")]
    VarCalculation(String),

    /// Compliance rule validation error
    #[error("Compliance validation error: {0}")]
    ComplianceValidation(String),

    /// Position limits validation error
    #[error("Position limits validation error: {0}")]
    LimitsValidation(String),

    /// Configuration setup or validation error
    #[error("Configuration error: {0}")]
    Configuration(String),

    /// Invalid input data error
    #[error("Invalid data: {0}")]
    InvalidData(String),
}

/// Result type for risk data operations
pub type RiskDataResult<T> = Result<T, RiskDataError>;

#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used)]
mod tests {
    use super::*;

    #[test]
    fn test_risk_data_config_default() {
        let config = RiskDataConfig::default();
        assert_eq!(config.database_url, "postgresql://localhost/foxhunt");
        assert_eq!(config.redis_url, "redis://localhost:6379");
        assert_eq!(config.max_connections, 10);
        assert_eq!(config.connection_timeout_secs, 30);
    }

    #[test]
    fn test_risk_data_error_display() {
        let error = RiskDataError::VarCalculation("Test error".to_string());
        assert_eq!(error.to_string(), "VaR calculation error: Test error");
    }
}
