//! Service infrastructure types
//!
//! Types for service identification, status, and configuration versioning.

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::fmt;
use uuid::Uuid;

// =============================================================================
// Core Data Types
// =============================================================================

/// Unique identifier for services
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ServiceId(pub String);

impl ServiceId {
    /// Create a new service ID
    pub fn new<S: Into<String>>(id: S) -> Self {
        Self(id.into())
    }

    /// Get the inner string value
    ///
    /// Get the execution ID as a string slice
    ///
    /// Get execution ID as string slice
    pub fn as_str(&self) -> &str {
        &self.0
    }
}

impl fmt::Display for ServiceId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl From<&str> for ServiceId {
    fn from(s: &str) -> Self {
        Self(s.to_owned())
    }
}

impl From<String> for ServiceId {
    fn from(s: String) -> Self {
        Self(s)
    }
}

/// Service status enumeration
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ServiceStatus {
    /// Service is starting up
    Starting,
    /// Service is running normally
    Running,
    /// Service is degraded but functional
    Degraded,
    /// Service is stopping
    Stopping,
    /// Service is stopped
    Stopped,
    /// Service has encountered an error
    Error,
    /// Service is in maintenance mode
    Maintenance,
}

impl fmt::Display for ServiceStatus {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Starting => write!(f, "STARTING"),
            Self::Running => write!(f, "RUNNING"),
            Self::Degraded => write!(f, "DEGRADED"),
            Self::Stopping => write!(f, "STOPPING"),
            Self::Stopped => write!(f, "STOPPED"),
            Self::Error => write!(f, "ERROR"),
            Self::Maintenance => write!(f, "MAINTENANCE"),
        }
    }
}

impl ServiceStatus {
    /// Check if the service is healthy
    pub const fn is_healthy(&self) -> bool {
        matches!(self, Self::Running | Self::Starting)
    }

    /// Check if the service is available for requests
    pub const fn is_available(&self) -> bool {
        matches!(self, Self::Running | Self::Degraded)
    }
}

/// Configuration version for tracking changes
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ConfigVersion {
    /// Version number
    pub version: u64,
    /// Timestamp when version was created
    pub timestamp: DateTime<Utc>,
    /// Optional description of changes
    pub description: Option<String>,
}

impl ConfigVersion {
    /// Create a new config version
    pub fn new(version: u64) -> Self {
        Self {
            version,
            timestamp: Utc::now(),
            description: None,
        }
    }

    /// Create a new config version with description
    pub fn with_description<S: Into<String>>(version: u64, description: S) -> Self {
        Self {
            version,
            timestamp: Utc::now(),
            description: Some(description.into()),
        }
    }
}

// TECHNICAL DEBT ELIMINATED - Use DateTime<Utc> directly instead of Timestamp alias

/// Timestamp type alias for consistency across the system
pub type Timestamp = DateTime<Utc>;

/// Request ID for tracing and correlation
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct RequestId(pub Uuid);

impl Default for RequestId {
    /// Create a default request ID with a new UUID
    fn default() -> Self {
        Self::new()
    }
}

impl RequestId {
    /// Generate a new random request ID
    pub fn new() -> Self {
        Self(Uuid::new_v4())
    }

    /// Create from UUID
    pub const fn from_uuid(uuid: Uuid) -> Self {
        Self(uuid)
    }

    /// Get the inner UUID
    pub const fn as_uuid(&self) -> Uuid {
        self.0
    }
}

impl fmt::Display for RequestId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}
