//! Identifier types and decimal extensions
//!
//! Newtype identifiers (EventId, FillId, AggregateId, AssetId, ClientId)
//! and the DecimalExt trait.

use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};
use std::fmt;

use super::CommonTypeError;

// =============================================================================
// CORE ID TYPES (MIGRATED FROM TRADING_ENGINE)
// =============================================================================

// Duplicate TradeId removed - using definition from line 1008

/// Event identifier for tracking system events
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct EventId(String);

impl EventId {
    /// Create a new random event ID
    pub fn new() -> Self {
        use uuid::Uuid;
        Self(Uuid::new_v4().to_string())
    }

    /// Create an event ID from a string, generating new if empty
    pub fn from_string<S: Into<String>>(id: S) -> Self {
        let id = id.into();
        if id.is_empty() {
            Self::new() // Generate new ID if empty
        } else {
            Self(id)
        }
    }

    /// Get the string value of the event ID
    pub fn value(&self) -> &str {
        &self.0
    }
}

impl fmt::Display for EventId {
    /// Format the event ID for display
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl From<String> for EventId {
    /// Create an `EventId` from a String
    fn from(s: String) -> Self {
        Self(s)
    }
}

impl Default for EventId {
    /// Create a default `EventId` with a new UUID
    fn default() -> Self {
        Self::new()
    }
}

// =============================================================================
// Decimal Extension Trait
// =============================================================================

/// Extension trait for `rust_decimal::Decimal` with convenience methods
pub trait DecimalExt {
    /// Create Decimal from f64, compatible with legacy `from_f64` usage
    fn from_f64(value: f64) -> Option<Self>
    where
        Self: Sized;

    /// Calculate square root of Decimal
    fn sqrt(&self) -> Option<Self>
    where
        Self: Sized;
}

impl DecimalExt for Decimal {
    fn from_f64(value: f64) -> Option<Self> {
        Decimal::from_f64_retain(value)
    }

    fn sqrt(&self) -> Option<Self> {
        if self.is_sign_negative() {
            return None;
        }
        let value_f64: f64 = self.to_string().parse().ok()?;
        let sqrt_f64 = value_f64.sqrt();
        Decimal::from_f64_retain(sqrt_f64)
    }
}

/// Fill identifier with validation
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct FillId(String);

impl FillId {
    /// Create a new fill ID with validation
    ///
    /// # Errors
    /// Returns error if the operation fails
    pub fn new<S: Into<String>>(id: S) -> Result<Self, CommonTypeError> {
        let id = id.into();
        if id.is_empty() {
            return Err(CommonTypeError::ValidationError {
                field: "fill_id".to_owned(),
                reason: "Fill ID cannot be empty".to_owned(),
            });
        }
        Ok(Self(id))
    }

    /// Get the fill ID as a string slice
    pub fn as_str(&self) -> &str {
        &self.0
    }
    /// Convert the fill ID into an owned string
    ///
    /// Convert the execution ID into an owned string
    ///
    /// Convert execution ID into owned string
    pub fn into_string(self) -> String {
        self.0
    }
}

impl fmt::Display for FillId {
    /// Format the fill ID for display
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

/// Aggregate identifier with validation
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct AggregateId(String);

impl AggregateId {
    /// Create a new aggregate ID with validation
    ///
    /// # Errors
    /// Returns error if the operation fails
    pub fn new<S: Into<String>>(id: S) -> Result<Self, CommonTypeError> {
        let id = id.into();
        if id.is_empty() {
            return Err(CommonTypeError::ValidationError {
                field: "aggregate_id".to_owned(),
                reason: "Aggregate ID cannot be empty".to_owned(),
            });
        }
        Ok(Self(id))
    }

    /// Get the aggregate ID as a string slice
    pub fn as_str(&self) -> &str {
        &self.0
    }
    /// Convert the aggregate ID into an owned string
    pub fn into_string(self) -> String {
        self.0
    }
}

impl fmt::Display for AggregateId {
    /// Format the aggregate ID for display
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

/// Asset identifier with validation
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct AssetId(String);

impl AssetId {
    /// Create a new asset ID with validation
    ///
    /// # Errors
    /// Returns error if the operation fails
    pub fn new<S: Into<String>>(id: S) -> Result<Self, CommonTypeError> {
        let id = id.into();
        if id.is_empty() {
            return Err(CommonTypeError::ValidationError {
                field: "asset_id".to_owned(),
                reason: "Asset ID cannot be empty".to_owned(),
            });
        }
        Ok(Self(id))
    }

    /// Get the asset ID as a string slice
    pub fn as_str(&self) -> &str {
        &self.0
    }
    /// Convert the asset ID into an owned string
    pub fn into_string(self) -> String {
        self.0
    }
}

impl fmt::Display for AssetId {
    /// Format the asset ID for display
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

/// Client identifier with validation
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ClientId(String);

impl ClientId {
    /// Create a new client ID with validation
    ///
    /// # Errors
    /// Returns error if the operation fails
    pub fn new<S: Into<String>>(id: S) -> Result<Self, CommonTypeError> {
        let id = id.into();
        if id.is_empty() {
            return Err(CommonTypeError::ValidationError {
                field: "client_id".to_owned(),
                reason: "Client ID cannot be empty".to_owned(),
            });
        }
        Ok(Self(id))
    }

    /// Get the client ID as a string slice
    pub fn as_str(&self) -> &str {
        &self.0
    }
    /// Convert the client ID into an owned string
    pub fn into_string(self) -> String {
        self.0
    }
}

impl fmt::Display for ClientId {
    /// Format the client ID for display
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}
