//! Backend (member) types

use serde::{Deserialize, Serialize};
use uuid::Uuid;

use crate::PoolId;

/// Unique identifier for a backend
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct BackendId(Uuid);

impl BackendId {
    /// Create a new random BackendId
    pub fn new() -> Self {
        Self(Uuid::new_v4())
    }

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

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

impl Default for BackendId {
    fn default() -> Self {
        Self::new()
    }
}

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

/// Backend operational status
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[derive(Default)]
pub enum BackendStatus {
    /// Backend is healthy and receiving traffic
    Online,
    /// Backend is administratively disabled
    Disabled,
    /// Backend is failing health checks
    Offline,
    /// Backend health is being checked
    Checking,
    /// Backend status is unknown
    #[default]
    Unknown,
}


/// Backend admin state
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[derive(Default)]
pub enum BackendAdminState {
    /// Backend is enabled
    #[default]
    Enabled,
    /// Backend is disabled
    Disabled,
    /// Backend is draining (no new connections)
    Drain,
}


/// Backend server (pool member)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Backend {
    /// Unique identifier
    pub id: BackendId,
    /// Human-readable name
    pub name: String,
    /// Parent pool
    pub pool_id: PoolId,
    /// IP address of the backend server
    pub address: String,
    /// Port number
    pub port: u16,
    /// Weight for weighted algorithms (1-100)
    pub weight: u32,
    /// Administrative state
    pub admin_state: BackendAdminState,
    /// Operational status (from health checks)
    pub status: BackendStatus,
    /// Creation timestamp
    pub created_at: u64,
    /// Last update timestamp
    pub updated_at: u64,
}

impl Backend {
    /// Create a new backend
    pub fn new(
        name: impl Into<String>,
        pool_id: PoolId,
        address: impl Into<String>,
        port: u16,
    ) -> Self {
        let now = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap_or_default()
            .as_secs();
        
        Self {
            id: BackendId::new(),
            name: name.into(),
            pool_id,
            address: address.into(),
            port,
            weight: 1,
            admin_state: BackendAdminState::Enabled,
            status: BackendStatus::Unknown,
            created_at: now,
            updated_at: now,
        }
    }

    /// Check if backend should receive traffic
    pub fn is_available(&self) -> bool {
        self.admin_state == BackendAdminState::Enabled && self.status == BackendStatus::Online
    }
}

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

    #[test]
    fn test_backend_creation() {
        let pool_id = PoolId::new();
        let backend = Backend::new("web-1", pool_id, "10.0.0.1", 8080);
        assert_eq!(backend.name, "web-1");
        assert_eq!(backend.address, "10.0.0.1");
        assert_eq!(backend.port, 8080);
        assert_eq!(backend.weight, 1);
    }

    #[test]
    fn test_backend_availability() {
        let pool_id = PoolId::new();
        let mut backend = Backend::new("web-1", pool_id, "10.0.0.1", 8080);
        
        // Unknown status - not available
        assert!(!backend.is_available());
        
        // Online - available
        backend.status = BackendStatus::Online;
        assert!(backend.is_available());
        
        // Disabled admin state - not available
        backend.admin_state = BackendAdminState::Disabled;
        assert!(!backend.is_available());
    }
}
