#![deny(clippy::unwrap_used, clippy::expect_used)]
#![cfg_attr(test, allow(clippy::unwrap_used, clippy::expect_used))]
#![allow(dead_code)]
#![allow(missing_docs)]
#![allow(missing_debug_implementations)]
#![allow(unused_crate_dependencies)]
#![allow(clippy::float_arithmetic)]
#![allow(clippy::non_ascii_literal)]
#![allow(clippy::str_to_string)]
#![allow(clippy::partial_pub_fields)]
#![allow(clippy::multiple_inherent_impl)]
#![allow(clippy::same_name_method)]
#![allow(clippy::shadow_reuse)]
#![allow(clippy::shadow_unrelated)]
#![allow(clippy::shadow_same)]
#![allow(clippy::doc_markdown)]
#![allow(clippy::indexing_slicing)]
#![allow(clippy::missing_const_for_fn)]
#![allow(clippy::module_name_repetitions)]
#![allow(clippy::integer_division)]
#![allow(clippy::cognitive_complexity)]
#![allow(clippy::similar_names)]
#![allow(clippy::clone_on_ref_ptr)]
#![allow(clippy::too_many_lines)]
#![allow(clippy::type_complexity)]
#![allow(clippy::single_char_lifetime_names)]
#![allow(clippy::as_conversions)]
#![allow(clippy::cast_precision_loss)]
#![allow(clippy::cast_possible_truncation)]
#![allow(clippy::default_numeric_fallback)]
#![allow(clippy::arithmetic_side_effects)]
#![allow(clippy::needless_range_loop)]
#![allow(clippy::into_iter_on_ref)]
#![allow(clippy::new_without_default)]
#![allow(clippy::manual_let_else)]
#![allow(clippy::unnecessary_wraps)]
#![allow(clippy::too_many_arguments)]
#![allow(clippy::must_use_candidate)]
#![allow(clippy::missing_errors_doc)]
#![allow(clippy::cast_sign_loss)]
#![allow(clippy::cast_possible_wrap)]
#![allow(clippy::cast_lossless)]
#![allow(clippy::unused_async)]
#![allow(clippy::match_same_arms)]
#![allow(clippy::unused_self)]
#![allow(clippy::map_err_ignore)]
#![allow(clippy::single_match_else)]
#![allow(clippy::wildcard_imports)]
#![allow(clippy::unnecessary_cast)]

//! Ensemble signal aggregation for trading models

use thiserror::Error;

// Re-export core types so sub-modules can use `crate::X`
pub use ml_core::{Features, HealthStatus, MLError, MLResult, ModelPrediction};
pub use common::model_types::ModelType;

pub mod ab_testing;
pub mod adaptive_ml_integration;
pub mod aggregator;
pub mod confidence;
pub mod conviction_gates;
pub mod coordinator;
pub mod coordinator_extended;
pub mod cuda_streams;
pub mod decision;
pub mod gate_optimizer;
pub mod hot_swap;
pub mod inference_adapter;
pub mod inference_ensemble;
pub mod metrics;
pub mod model;
pub mod signal;
pub mod stream_ensemble;
pub mod training_integration;
pub mod voting;
pub mod weight_optimizer;
pub mod weights;

// Re-export key types that are used across ensemble modules
pub use ab_testing::{
    ABGroup, ABMetricsTracker, ABTestConfig, ABTestResults, ABTestRouter, GroupMetrics,
    Recommendation, StatisticalTestResult,
};
pub use adaptive_ml_integration::{
    AdaptiveMLEnsemble, AdaptiveMetrics, MarketRegime, PricePoint, RegimeConfig,
};
pub use aggregator::{ModelSignal, SignalMetadata, SignalStatistics};
pub use confidence::{
    AggregationConfig, AleatoricConfig, CalibrationParams, CombinationMethod,
    ConfidenceAggregator, DisagreementRecord, DisagreementTracker, EnsemblePredictionWithUncertainty,
    EpistemicConfig, IntervalCombiner, ModelContribution, PredictionInterval, ReliabilityRecord,
    ReliabilityScorer, UncertaintyDecomposition, UncertaintyQuantifier, VarianceEstimationMethod,
};
pub use conviction_gates::{
    ConvictionGateConfig, ConvictionGateEvaluator, ConvictionGateOutcome, GateEvaluation,
    GateInput, GatePassResult, GateRejection, TradingSession,
};
pub use coordinator::{EnsembleCoordinator, ModelRegistry, SignalAggregator};
pub use coordinator_extended::{
    DiversityAnalyzer, DiversityMetrics, EnsembleConfig as ExtendedEnsembleConfig,
    ExtendedEnsembleCoordinator, ModelPerformance, PerformanceAttribution, PerformanceTracker,
    SupportedModel, WeightSnapshot,
};
pub use decision::{EnsembleDecision, ModelVote, ModelWeight, PerformanceMetrics, TradingAction};
pub use gate_optimizer::{
    GateBucketMetrics, GateOptimizationResult, GateOptimizer, GateOptimizerConfig,
    ThresholdAdjustment,
};
pub use hot_swap::{
    CanaryMetrics, CanaryResult, CheckpointModel, CheckpointValidator, HotSwapManager,
    ModelBufferPair, RollbackPolicy, ValidationResult,
};
pub use inference_adapter::{EnsemblePrediction, FeatureVector, ModelInferenceAdapter, PredictionMeta};
pub use metrics::{
    EnsembleMetrics, CANARY_MONITORING_TOTAL, CHECKPOINT_SWAPS_TOTAL,
    CHECKPOINT_SWAP_LATENCY_MICROSECONDS, CHECKPOINT_VALIDATION_TOTAL,
};
pub use training_integration::EnsembleTrainingIntegration;
pub use weight_optimizer::{
    ModelRollingMetrics, OptimizationResult, WeightAdjustment, WeightOptimizer,
    WeightOptimizerConfig,
};

/// Errors that can occur in ensemble operations
#[derive(Error, Debug)]
pub enum EnsembleError {
    #[error("Failed to acquire lock: {0}")]
    LockAcquisitionFailed(String),

    #[error("Invalid ensemble configuration: {0}")]
    InvalidConfiguration(String),

    #[error("Model not found: {0}")]
    ModelNotFound(String),

    #[error("Insufficient models for ensemble: expected {expected}, got {actual}")]
    InsufficientModels { expected: usize, actual: usize },

    #[error("Weight calculation failed: {0}")]
    WeightCalculationFailed(String),

    #[error("Aggregation failed: {0}")]
    AggregationFailed(String),
}

// `From<EnsembleError> for MLError` lives here because ml-ensemble owns
// EnsembleError (local) and imports MLError from ml-core (dependency).
// This satisfies the orphan rule: EnsembleError is a local type parameter.
impl From<EnsembleError> for MLError {
    fn from(err: EnsembleError) -> Self {
        match err {
            EnsembleError::InvalidConfiguration(msg) => MLError::ConfigError(msg),
            EnsembleError::ModelNotFound(msg) => MLError::ModelNotFound(msg),
            EnsembleError::InsufficientModels { expected, actual } => {
                MLError::ValidationError {
                    message: format!(
                        "Insufficient models: expected {}, got {}",
                        expected, actual
                    ),
                }
            }
            EnsembleError::LockAcquisitionFailed(msg) => MLError::LockError(msg),
            EnsembleError::WeightCalculationFailed(msg) => {
                MLError::ModelError(format!("Weight calculation failed: {}", msg))
            }
            EnsembleError::AggregationFailed(msg) => {
                MLError::InferenceError(format!("Aggregation failed: {}", msg))
            }
        }
    }
}
