//! Common types and utilities for ML models

// Price imported from crate root (lib.rs)
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::PathBuf;
use std::time::SystemTime;
use uuid::Uuid;
// Import from common types with explicit path
use common::types::{Price, Quantity, Symbol, Volume};
use rust_decimal::Decimal;

pub mod action;
pub mod circuit_breaker;
pub mod config;
pub mod metrics;
pub mod performance;

// Production ML types
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModelVersion {
    pub version: String,
    pub model_id: Uuid,
    pub created_at: SystemTime,
    pub commit_hash: String,
    pub model_type: String,
    pub performance_metrics: PerformanceMetrics,
    pub onnx_config: Option<ONNXExportConfig>,
    pub artifacts: ModelArtifacts,
    pub validation_results: ValidationResults,
    pub tags: Vec<String>,
    pub description: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceMetrics {
    pub avg_latency_us: f64,
    pub p99_latency_us: f64,
    pub throughput_ips: f64,
    pub memory_usage_mb: f64,
    pub accuracy: f64,
    pub energy_consumption_mj: Option<f64>,
    pub hardware_metrics: HardwareMetrics,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HardwareMetrics {
    pub cpu_utilization: f64,
    pub gpu_utilization: Option<f64>,
    pub memory_bandwidth: f64,
    pub cache_metrics: HashMap<String, f64>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModelArtifacts {
    pub pytorch_model: PathBuf,
    pub onnx_model: Option<PathBuf>,
    pub bf16_model: Option<PathBuf>,
    pub tensorrt_engine: Option<PathBuf>,
    pub optimization_logs: Option<PathBuf>,
    pub training_data: Option<PathBuf>,
    pub config_file: PathBuf,
    pub benchmark_results: Option<PathBuf>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValidationResults {
    pub test_accuracy: f64,
    pub business_metrics: HashMap<String, f64>,
    pub latency_distribution: LatencyDistribution,
    pub stress_test_passed: bool,
    pub ab_test_results: Option<ABTestResults>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LatencyDistribution {
    pub min_us: f64,
    pub max_us: f64,
    pub mean_us: f64,
    pub median_us: f64,
    pub p95_us: f64,
    pub p99_us: f64,
    pub p999_us: f64,
    pub std_dev_us: f64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ABTestResults {
    pub control_accuracy: f64,
    pub treatment_accuracy: f64,
    pub statistical_significance: f64,
    pub confidence_interval: (f64, f64),
    pub sample_size: usize,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PrecisionConfig {
    pub precision: String, // "bf16", "f32"
    pub accuracy_threshold: f64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ONNXExportConfig {
    pub opset_version: i64,
    pub optimization_level: String,
    pub enable_tensorrt: bool,
    pub dynamic_axes: HashMap<String, Vec<i64>>,
}

// Direct use of canonical types - no compatibility wrappers

/// `Market` data structure compatible with ML models
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
/// MarketData component.
pub struct MarketData {
    pub asset_id: Symbol,
    pub price: Price,
    pub volume: Volume,
    pub bid: Price,
    pub ask: Price,
    pub bid_size: Volume,
    pub ask_size: Volume,
    pub timestamp: u64, // Unix timestamp in nanoseconds
}

// Precision factor compatible with canonical Price type (8 decimal places)
/// `PRECISION_FACTOR`: component.
pub const PRECISION_FACTOR: i64 = 100_000_000; // 10^8

/// Systematic conversion utilities for interfacing with different precision systems
/// ELIMINATES IntegerPrice usage throughout ML crate
pub mod conversions {

    use super::*;

    // NOTE: price_to_liquid_fixed_point() and liquid_fixed_point_to_price()
    // are in the `ml` crate's common::conversions module because they depend on
    // ml::liquid::FixedPoint which is not available in ml-core.

    /// Convert `f64` to canonical Price with full 8-decimal precision
    pub fn f64_to_price(value: f64) -> Result<Price, Box<dyn std::error::Error>> {
        // error_handling::TradingError replaced
        Price::from_f64(value)
            .map_err(|e| format!("Invalid f64 value for Price conversion: {}", e).into())
    }

    /// Convert canonical Price to `f64` for ML model inputs
    pub fn price_to_f64(price: Price) -> Result<f64, Box<dyn std::error::Error>> {
        Ok(price.to_f64())
    }

    /// SYSTEMATIC CONVERSION TRAITS: Eliminate IntegerPrice usage throughout ML
    /// These traits provide compile-time guaranteed conversions between types
    /// Convert Price to Decimal for database/API operations
    pub fn price_to_decimal(price: Price) -> Result<Decimal, Box<dyn std::error::Error>> {
        Ok(price.to_decimal()?)
    }

    /// Convert Decimal to Price for trading operations
    pub fn decimal_to_price(decimal: Decimal) -> Price {
        Price::from_decimal(decimal)
    }

    /// Convert Volume to f64 for ML model inputs
    pub fn volume_to_f64(volume: Volume) -> Result<f64, Box<dyn std::error::Error>> {
        Ok(volume.to_f64())
    }

    /// Convert f64 to Volume with validation
    pub fn f64_to_volume(value: f64) -> Result<Volume, Box<dyn std::error::Error>> {
        if value < 0.0 {
            return Err("Volume cannot be negative".into());
        }
        Volume::from_f64(value).map_err(|e| format!("Invalid volume value: {}", e).into())
    }

    /// Convert Quantity to i64 for efficient processing
    pub fn quantity_to_i64(quantity: Quantity) -> Result<i64, Box<dyn std::error::Error>> {
        let quantity_f64 = quantity.to_f64();
        Ok((quantity_f64 * 100_000_000.0) as i64) // Convert to integer with 8 decimal precision
    }

    /// Convert i64 to Quantity with validation
    pub fn i64_to_quantity(value: i64) -> Result<Quantity, Box<dyn std::error::Error>> {
        if value < 0 {
            return Err("Quantity cannot be negative".into());
        }
        Ok(Quantity::from_f64(value as f64 / 100_000_000.0).unwrap_or(Quantity::ZERO))
    }

    /// Batch convert prices to f64 vector for ML model inputs
    pub fn prices_to_f64_vec(prices: &[Price]) -> Vec<f64> {
        prices.iter().map(|p| p.to_f64()).collect()
    }

    /// Batch convert f64 vector to prices with validation
    pub fn f64_vec_to_prices(values: &[f64]) -> Result<Vec<Price>, Box<dyn std::error::Error>> {
        values
            .iter()
            .map(|&v| f64_to_price(v))
            .collect::<Result<Vec<_>, _>>()
    }
}
