// Enable pedantic warnings FIRST so individual allows below override them
#![warn(clippy::all)]
#![warn(clippy::pedantic)]
#![warn(clippy::cargo)]
#![allow(clippy::multiple_crate_versions)] // Workspace-level dependency concern
#![allow(clippy::cargo_common_metadata)] // Metadata managed at workspace level
// Safety denials and test overrides
#![deny(clippy::unwrap_used, clippy::expect_used)]
#![cfg_attr(test, allow(clippy::unwrap_used, clippy::expect_used))]
#![allow(unused_extern_crates)]
#![allow(unused_crate_dependencies)]
#![allow(missing_docs)]
#![allow(missing_debug_implementations)]
// Clippy pedantic lints that are acceptable in financial/risk code
#![allow(clippy::default_numeric_fallback)] // Float literals are contextually typed in financial code
#![allow(clippy::float_arithmetic)] // Financial calculations require floating-point arithmetic
#![allow(clippy::arithmetic_side_effects)] // Risk calculations use saturating/checked arithmetic where needed
#![allow(clippy::cast_precision_loss)] // Acceptable in statistical/risk calculations with proper validation
#![allow(clippy::missing_errors_doc)] // Error documentation is in module-level docs
#![allow(clippy::cast_possible_truncation)] // Type conversions validated in context
#![allow(clippy::cast_sign_loss)] // Sign loss is validated in conversion functions
#![allow(clippy::cast_possible_wrap)] // Wrap-around is validated in context
#![allow(clippy::as_conversions)] // Type conversions are carefully managed in risk code
#![allow(clippy::map_err_ignore)] // Error context preserved in error types
#![allow(clippy::unused_async)] // Async needed for trait implementations and future expansion
#![allow(clippy::module_name_repetitions)] // Module prefixes provide clarity in risk domain
#![allow(clippy::similar_names)] // Financial variables often have similar names (var, cvar, etc.)
#![allow(clippy::shadow_reuse)] // Variable shadowing is intentional for transformations
#![allow(clippy::indexing_slicing)] // Bounds checked in context
#![allow(clippy::wildcard_enum_match_arm)] // Exhaustive matching not required for all enums
#![allow(clippy::cognitive_complexity)] // Risk calculations are inherently complex
#![allow(clippy::too_many_lines)] // Complex risk functions need many lines
#![allow(clippy::must_use_candidate)] // Not all functions need must_use
#![allow(clippy::used_underscore_binding)] // Underscore bindings used for partial pattern matches
#![allow(clippy::unused_self)] // Self parameter needed for trait consistency
#![allow(clippy::unreadable_literal)] // Large numbers are clear in financial context
#![allow(clippy::inline_always)] // Performance-critical code needs inlining hints
#![allow(clippy::else_if_without_else)] // Exhaustive else not always needed
#![allow(clippy::partial_pub_fields)] // Intentional mixed visibility for safety
#![allow(clippy::unnecessary_safety_doc)] // Safety docs retained for clarity
#![allow(clippy::let_underscore_must_use)] // Intentional discarding of must_use
#![allow(clippy::redundant_clone)] // Clones needed for ownership
#![allow(clippy::shadow_unrelated)] // Shadowing is intentional
#![allow(clippy::empty_structs_with_brackets)] // Explicit struct syntax preferred
#![allow(clippy::to_string_trait_impl)] // String conversion is intentional
#![allow(clippy::infinite_loop)] // Infinite loops are intentional (servers, event loops)
#![allow(clippy::multiple_inherent_impl)] // Multiple impl blocks for organization
#![allow(clippy::unnecessary_safety_comment)] // Safety comments retained for code clarity
#![allow(clippy::string_to_string)] // String cloning is intentional for ownership
// Additional pedantic allows needed by this crate
#![allow(clippy::missing_const_for_fn)] // const fn not needed for risk calculations
#![allow(clippy::unnecessary_wraps)]
#![allow(clippy::match_same_arms)]
#![allow(clippy::manual_let_else)]
#![allow(clippy::needless_pass_by_value)]
#![allow(clippy::map_unwrap_or)]
#![allow(clippy::doc_markdown)]
#![allow(clippy::clone_on_ref_ptr)]
#![allow(clippy::uninlined_format_args)]
#![allow(clippy::unnecessary_literal_bound)]
#![allow(clippy::single_match_else)]
#![allow(clippy::should_implement_trait)]
#![allow(clippy::derivable_impls)]
#![allow(clippy::doc_lazy_continuation)]
#![allow(clippy::cast_lossless)]
#![allow(clippy::trivially_copy_pass_by_ref)]
#![allow(clippy::same_item_push)]
#![allow(clippy::no_effect_underscore_binding)]
#![allow(clippy::iter_without_into_iter)]
#![allow(clippy::assigning_clones)]
#![allow(clippy::manual_clamp)]
#![allow(clippy::if_same_then_else)] // Explicit arms for clarity
#![allow(clippy::new_without_default)]
#![allow(clippy::redundant_closure)]
#![allow(clippy::io_other_error)]
// Additional allows for risk-specific patterns
#![allow(clippy::too_many_arguments)] // Risk functions need many parameters
#![allow(clippy::struct_excessive_bools)] // Boolean flags for risk state
#![allow(clippy::needless_range_loop)] // Index loops in Monte Carlo simulations
#![allow(clippy::manual_flatten)] // Explicit iteration preferred
#![allow(clippy::field_reassign_with_default)] // Default then override pattern
#![allow(clippy::declare_interior_mutable_const)] // Intentional const patterns
#![allow(clippy::inherent_to_string)] // Custom Display implementations
#![allow(clippy::vec_init_then_push)] // Sequential construction preferred
#![allow(clippy::type_complexity)] // Complex types needed for risk calculations
#![allow(clippy::incompatible_msrv)] // MSRV not strictly enforced
#![allow(clippy::negative_feature_names)] // Feature naming is intentional
#![allow(clippy::redundant_feature_names)] // Feature naming conventions
//! Risk Management Module
//!
//! This module provides comprehensive risk management functionality for HFT trading systems.
//! It includes Value at Risk (`VaR`) calculations, position tracking, stress testing, circuit breakers,
//! safety systems, and compliance monitoring.
//!
//! # Features
//!
//! - **`VaR` Calculation Engine**: Multiple methodologies (Historical Simulation, Monte Carlo, Parametric, Expected Shortfall)
//! - **Real-time Position Tracking**: Concentration risk monitoring with HHI calculations
//! - **Safety Systems**: Atomic kill switches, emergency response, position limiters
//! - **Circuit Breakers**: Dynamic portfolio protection with Redis coordination
//! - **Stress Testing**: Scenario analysis with Monte Carlo simulations
//! - **Compliance Monitoring**: Regulatory position limits and risk validation
//! - **Risk Engine**: Real-time risk validation and monitoring
//!
//! # Quick Start
//!
//! ```rust,no_run
//! use risk::prelude::*;
//!
//! #[tokio::main]
//! async fn main() -> Result<(), RiskError> {
//!     // Initialize risk engine
//!     let config = RiskConfig::default();
//!     let mut risk_engine = RiskEngine::new(config).await?;
//!
//!     // Create a position tracker
//!     let position_tracker = PositionTracker::new();
//!
//!     // Initialize VaR calculator
//!     let var_engine = RealVaREngine::new();
//!
//!     // Perform risk check on an order
//!     let order_info = OrderInfo {
//!         symbol: Symbol::from("AAPL"),
//!         side: OrderSide::Buy,
//!         quantity: Quantity::new(100.0)?,
//!         price: Price::new(150.0)?,
//!     };
//!
//!     let risk_result = risk_engine.validate_order(&order_info).await?;
//!     println!("Risk check result: {:?}", risk_result);
//!
//!     Ok(())
//! }
//! ```
//!
//! # Architecture
//!
//! The risk module is structured around several core components:
//!
//! ## Core Components
//!
//! - **Risk Engine**: Central coordinator for all risk calculations and validations
//! - **Position Tracker**: Real-time position monitoring with concentration limits
//! - **`VaR` Calculator**: Multiple methodologies for portfolio risk assessment
//! - **Safety Systems**: Emergency controls and automated risk responses
//! - **Circuit Breakers**: Dynamic protection against market anomalies
//! - **Stress Tester**: Scenario analysis and portfolio stress testing
//! - **Compliance Monitor**: Regulatory compliance and position validation
//!
//! ## Safety Architecture
//!
//! The safety systems provide multiple layers of protection:
//!
//! 1. **Position Limits**: Hard limits on position sizes and concentrations
//! 2. **Kill Switches**: Atomic emergency stops with Redis broadcasting
//! 3. **Circuit Breakers**: Dynamic portfolio-based protection
//! 4. **Emergency Response**: Automated incident response and escalation
//! 5. **Compliance Checks**: Regulatory position limits and validation
//!
//! # Configuration
//!
//! The risk module can be configured via environment variables or configuration files:
//!
//! ```rust
//! use risk::RiskConfig;
//!
//! let config = RiskConfig {
//!     max_position_size: Price::new(1_000_000.0).unwrap(),
//!     max_daily_loss: Price::new(100_000.0).unwrap(),
//!     var_confidence_level: 0.95,
//!     var_lookback_days: 252,
//!     enable_kill_switch: true,
//!     enable_circuit_breakers: true,
//!     redis_url: "redis://localhost:6379".to_string(),
//! };
//! ```

// Core modules
pub mod error;
// pub mod risk_types; // DELETED - duplicate types eliminated
pub mod operations;

// Risk calculation engines
pub mod kelly_sizing;
pub mod portfolio_optimization;
pub mod position_tracker;
pub mod risk_engine;
pub mod stress_tester;
pub mod var_calculator;

// Risk type definitions
pub mod risk_types;

// Safety and protection systems
pub mod circuit_breaker;
pub mod compliance;
pub mod drawdown_monitor;
pub mod safety;

// Risk enforcement and correlation monitoring
pub mod enforcement;
pub mod correlation_monitor;

// RE-EXPORTS FOR TEST COMPATIBILITY
// The following re-exports are required for test suite compilation
// Tests import these types directly from the risk crate

// Export key types from submodules for test compatibility
pub use kelly_sizing::KellySizer;
pub use risk_engine::RiskEngine;
pub use safety::kill_switch::AtomicKillSwitch;
pub use stress_tester::StressTester;
pub use var_calculator::var_engine::RealVaREngine;

// Export compliance types first
pub use compliance::ComplianceValidator;

// Type aliases for backward compatibility with tests
pub use ComplianceValidator as ComplianceEngine;
pub use RealVaREngine as VaRCalculator;

// ELIMINATED: Prelude module removed to force explicit imports

/// Library version
pub const VERSION: &str = env!("CARGO_PKG_VERSION");

/// Library name
pub const NAME: &str = env!("CARGO_PKG_NAME");

/// Get risk module information
#[must_use]
pub fn info() -> RiskModuleInfo {
    RiskModuleInfo {
        name: NAME.to_owned(),
        version: VERSION.to_owned(),
        description: "Enterprise Risk Management for HFT Trading Systems".to_owned(),
        features: vec![
            "Value at Risk Calculations (Multiple Methodologies)".to_owned(),
            "Real-time Position Tracking".to_owned(),
            "Concentration Risk Monitoring".to_owned(),
            "Atomic Kill Switch Systems".to_owned(),
            "Dynamic Circuit Breakers".to_owned(),
            "Stress Testing and Scenario Analysis".to_owned(),
            "Compliance Monitoring".to_owned(),
            "Emergency Response Systems".to_owned(),
            "Kelly Criterion Position Sizing".to_owned(),
            "Drawdown Protection".to_owned(),
        ],
        methodologies: vec![
            "Historical Simulation VaR".to_owned(),
            "Monte Carlo VaR".to_owned(),
            "Parametric VaR".to_owned(),
            "Expected Shortfall (CVaR)".to_owned(),
        ],
    }
}

/// Risk module information structure
#[derive(Debug, Clone)]
pub struct RiskModuleInfo {
    /// Module name
    pub name: String,
    /// Version string
    pub version: String,
    /// Description
    pub description: String,
    /// Feature list
    pub features: Vec<String>,
    /// Risk methodologies supported
    pub methodologies: Vec<String>,
}

use std::fmt;

impl fmt::Display for RiskModuleInfo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        writeln!(f, "{} v{}", self.name, self.version)?;
        writeln!(f, "{}", self.description)?;
        writeln!(f, "\nFeatures:")?;
        for feature in &self.features {
            writeln!(f, "  \u{2022} {feature}")?;
        }
        writeln!(f, "\nRisk Methodologies:")?;
        for methodology in &self.methodologies {
            writeln!(f, "  \u{2022} {methodology}")?;
        }
        Ok(())
    }
}

/// Initialize the risk module with logging
///
/// # Errors
///
/// Returns error if:
/// - Logging initialization fails
/// - Environment variables are invalid
pub fn init() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    // Initialize tracing subscriber if not already initialized
    if std::env::var("RUST_LOG").is_err() {
        std::env::set_var("RUST_LOG", "info");
    }

    tracing_subscriber::fmt::try_init().map_err(|_| "Failed to initialize logging")?;

    tracing::info!("Initialized Risk Management Module {} v{}", NAME, VERSION);
    Ok(())
}

/// Validate risk configuration
///
/// # Errors
///
/// Returns error if:
/// - Kill switch configuration is invalid (empty channels)
/// - Position limits are non-positive
/// - Maximum order value is zero or negative
/// - Daily loss limit is invalid
/// - Redis URL is empty
/// - Emergency response configuration is invalid
pub fn validate_risk_config(config: &SafetyConfig) -> Result<(), String> {
    // Validate basic configuration
    if !config.enabled {
        tracing::warn!("Risk management is disabled - this should only be used in testing");
    }

    // Validate kill switch configuration
    if config.kill_switch.enabled {
        if config.kill_switch.global_channel.is_empty() {
            return Err("Kill switch global channel cannot be empty".to_owned());
        }

        if config.kill_switch.strategy_channel_prefix.is_empty() {
            return Err("Kill switch strategy channel prefix cannot be empty".to_owned());
        }
    }

    // Validate position limits
    if config.position_limits.enabled {
        if config.position_limits.max_position_per_symbol <= 0.0 {
            return Err("Maximum position per symbol must be positive".to_owned());
        }

        if config.position_limits.max_order_value <= 0.0 {
            return Err("Maximum order value must be positive".to_owned());
        }

        if config.position_limits.max_daily_loss <= 0.0 {
            return Err("Maximum daily loss must be positive".to_owned());
        }
    }

    // Validate Redis URL
    if config.redis_url.is_empty() {
        return Err("Redis URL cannot be empty".to_owned());
    }

    // Validate emergency response
    if config.emergency_response.enabled {
        if config.emergency_response.emergency_contacts.is_empty() {
            tracing::warn!("No emergency contacts configured for incident response");
        }

        if config.emergency_response.max_consecutive_violations == 0 {
            return Err("Max consecutive violations must be greater than 0".to_owned());
        }
    }

    Ok(())
}

use crate::safety::{
    EmergencyResponseConfig, KillSwitchConfig, PositionLimiterConfig, SafetyConfig,
};
use common::types::Price;

/// Get default configuration for development/testing
#[must_use]
pub fn development_config() -> SafetyConfig {
    SafetyConfig {
        enabled: true,
        kill_switch: KillSwitchConfig {
            enabled: true,
            global_channel: "foxhunt:dev:kill_switch:global".to_owned(),
            strategy_channel_prefix: "foxhunt:dev:kill_switch:strategy".to_owned(),
            symbol_channel_prefix: "foxhunt:dev:kill_switch:symbol".to_owned(),
            auto_recovery_enabled: true,
            auto_recovery_delay: std::time::Duration::from_secs(60), // 1 minute in dev
        },
        position_limits: PositionLimiterConfig {
            enabled: true,
            cache_ttl: std::time::Duration::from_secs(30),
            rpc_check_threshold_percent: 0.5, // Lower threshold for development
            max_position_per_symbol: 10_000.0, // $10K max per symbol in dev
            max_order_value: 5_000.0,         // $5K max per order in dev
            max_daily_loss: 1_000.0,          // $1K daily loss limit in dev
        },
        emergency_response: EmergencyResponseConfig {
            enabled: true,
            loss_check_interval: std::time::Duration::from_secs(30),
            position_check_interval: std::time::Duration::from_secs(15),
            max_consecutive_violations: 3,
            emergency_contacts: vec!["dev@foxhunt.com".to_owned()],
            max_daily_loss: Price::new(1000.0).unwrap_or(Price::ZERO),
            max_drawdown: Price::new(2000.0).unwrap_or(Price::ZERO),
        },
        redis_url: "redis://localhost:6379".to_owned(),
        safety_check_timeout: std::time::Duration::from_millis(50), // Longer timeout for dev
    }
}

/// Get configuration for production deployment
#[must_use]
pub fn production_config() -> SafetyConfig {
    SafetyConfig {
        enabled: true,
        kill_switch: KillSwitchConfig {
            enabled: true,
            global_channel: "foxhunt:prod:kill_switch:global".to_owned(),
            strategy_channel_prefix: "foxhunt:prod:kill_switch:strategy".to_owned(),
            symbol_channel_prefix: "foxhunt:prod:kill_switch:symbol".to_owned(),
            auto_recovery_enabled: false, // Manual recovery in production
            auto_recovery_delay: std::time::Duration::from_secs(1800), // 30 minutes
        },
        position_limits: PositionLimiterConfig {
            enabled: true,
            cache_ttl: std::time::Duration::from_secs(10), // Shorter cache in production
            rpc_check_threshold_percent: 0.9,              // Higher threshold for production
            max_position_per_symbol: 100_000.0,            // $100K max per symbol
            max_order_value: 50_000.0,                     // $50K max per order
            max_daily_loss: 10_000.0,                      // $10K daily loss limit
        },
        emergency_response: EmergencyResponseConfig {
            enabled: true,
            loss_check_interval: std::time::Duration::from_secs(5),
            position_check_interval: std::time::Duration::from_secs(2),
            max_consecutive_violations: 5,
            emergency_contacts: vec![
                "risk@foxhunt.com".to_owned(),
                "trading@foxhunt.com".to_owned(),
                "alerts@foxhunt.com".to_owned(),
            ],
            max_daily_loss: Price::new(10_000.0).unwrap_or(Price::ZERO),
            max_drawdown: Price::new(25_000.0).unwrap_or(Price::ZERO),
        },
        redis_url: std::env::var("REDIS_URL")
            .unwrap_or_else(|_| "redis://redis-cluster:6379".to_owned()),
        safety_check_timeout: std::time::Duration::from_millis(5), // Very tight timeout in production
    }
}

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

    #[test]
    fn test_module_info() {
        let info = info();
        assert_eq!(info.name, "risk");
        assert!(!info.version.is_empty());
        assert!(!info.description.is_empty());
        assert!(!info.features.is_empty());
        assert!(!info.methodologies.is_empty());
    }

    #[test]
    fn test_development_config_validation() {
        let config = development_config();
        assert!(validate_risk_config(&config).is_ok());
        assert!(config.enabled);
        assert!(config.kill_switch.enabled);
        assert!(config.position_limits.enabled);
        assert!(config.emergency_response.enabled);
    }

    #[test]
    fn test_production_config_validation() {
        let config = production_config();
        assert!(validate_risk_config(&config).is_ok());
        assert!(config.enabled);
        assert!(!config.kill_switch.auto_recovery_enabled); // Manual recovery in prod
        assert!(config.position_limits.max_position_per_symbol > 0.0);
        assert!(!config.emergency_response.emergency_contacts.is_empty());
    }

    #[test]
    fn test_invalid_config_validation() {
        let mut config = development_config();

        // Test empty kill switch channel
        config.kill_switch.global_channel = String::new();
        assert!(validate_risk_config(&config).is_err());

        // Reset and test invalid position limits
        config = development_config();
        config.position_limits.max_position_per_symbol = 0.0;
        assert!(validate_risk_config(&config).is_err());

        // Reset and test empty Redis URL
        config = development_config();
        config.redis_url = String::new();
        assert!(validate_risk_config(&config).is_err());
    }
}
