//! Backend pool types

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

use crate::LoadBalancerId;

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

impl PoolId {
    /// Create a new random PoolId
    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 PoolId {
    fn default() -> Self {
        Self::new()
    }
}

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

/// Load balancing algorithm
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[derive(Default)]
pub enum PoolAlgorithm {
    /// Round-robin distribution
    #[default]
    RoundRobin,
    /// Least connections
    LeastConnections,
    /// IP hash (sticky sessions by source IP)
    IpHash,
    /// Weighted round-robin
    WeightedRoundRobin,
    /// Random selection
    Random,
    /// Maglev consistent hashing (L4, stable backend selection)
    Maglev,
}


/// Pool protocol
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[derive(Default)]
pub enum PoolProtocol {
    /// TCP (L4)
    #[default]
    Tcp,
    /// UDP (L4)
    Udp,
    /// HTTP (L7)
    Http,
    /// HTTPS (L7)
    Https,
}


/// Backend pool - group of backend servers
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Pool {
    /// Unique identifier
    pub id: PoolId,
    /// Human-readable name
    pub name: String,
    /// Parent load balancer
    pub loadbalancer_id: LoadBalancerId,
    /// Load balancing algorithm
    pub algorithm: PoolAlgorithm,
    /// Protocol
    pub protocol: PoolProtocol,
    /// Session persistence (sticky sessions)
    pub session_persistence: Option<SessionPersistence>,
    /// Creation timestamp
    pub created_at: u64,
    /// Last update timestamp
    pub updated_at: u64,
}

impl Pool {
    /// Create a new pool
    pub fn new(
        name: impl Into<String>,
        loadbalancer_id: LoadBalancerId,
        algorithm: PoolAlgorithm,
        protocol: PoolProtocol,
    ) -> Self {
        let now = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap_or_default()
            .as_secs();
        
        Self {
            id: PoolId::new(),
            name: name.into(),
            loadbalancer_id,
            algorithm,
            protocol,
            session_persistence: None,
            created_at: now,
            updated_at: now,
        }
    }
}

/// Session persistence configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SessionPersistence {
    /// Persistence type
    pub persistence_type: PersistenceType,
    /// Cookie name (for cookie-based persistence)
    pub cookie_name: Option<String>,
    /// Timeout in seconds
    pub timeout_seconds: u32,
}

/// Session persistence type
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PersistenceType {
    /// Source IP affinity
    SourceIp,
    /// Cookie-based (L7 only)
    Cookie,
    /// App cookie (L7 only)
    AppCookie,
}

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

    #[test]
    fn test_pool_creation() {
        let lb_id = LoadBalancerId::new();
        let pool = Pool::new("web-pool", lb_id, PoolAlgorithm::RoundRobin, PoolProtocol::Http);
        assert_eq!(pool.name, "web-pool");
        assert_eq!(pool.algorithm, PoolAlgorithm::RoundRobin);
        assert_eq!(pool.protocol, PoolProtocol::Http);
    }
}
