//! L7 Policy types for HTTP/HTTPS routing

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

use crate::{ListenerId, PoolId};

/// Unique identifier for an L7 policy
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct L7PolicyId(Uuid);

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

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

/// L7 routing policy
///
/// Defines content-based routing rules for HTTP/HTTPS listeners.
/// Multiple policies can be attached to a listener and are evaluated
/// in order of their position field (lower = higher priority).
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct L7Policy {
    /// Unique identifier
    pub id: L7PolicyId,
    /// Parent listener
    pub listener_id: ListenerId,
    /// Human-readable name
    pub name: String,

    /// Evaluation order (lower = higher priority)
    pub position: u32,

    /// Action to take when rules match
    pub action: L7PolicyAction,

    /// Redirect URL (for RedirectToUrl action)
    pub redirect_url: Option<String>,

    /// Target pool (for RedirectToPool action)
    pub redirect_pool_id: Option<PoolId>,

    /// HTTP status code for redirects/rejects (e.g., 301, 302, 403, 503)
    pub redirect_http_status_code: Option<u16>,

    /// Whether this policy is active
    pub enabled: bool,

    /// Creation timestamp (Unix epoch)
    pub created_at: u64,
    /// Last update timestamp (Unix epoch)
    pub updated_at: u64,
}

/// Policy action when rules match
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum L7PolicyAction {
    /// Route to a specific pool (most common)
    RedirectToPool,
    /// Return HTTP redirect to URL
    RedirectToUrl,
    /// Reject request with status code
    Reject,
}

impl Default for L7PolicyAction {
    fn default() -> Self {
        Self::RedirectToPool
    }
}

impl L7Policy {
    /// Create a new L7 policy
    pub fn new(
        name: impl Into<String>,
        listener_id: ListenerId,
        position: u32,
        action: L7PolicyAction,
    ) -> Self {
        let now = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap_or_default()
            .as_secs();

        Self {
            id: L7PolicyId::new(),
            listener_id,
            name: name.into(),
            position,
            action,
            redirect_url: None,
            redirect_pool_id: None,
            redirect_http_status_code: None,
            enabled: true,
            created_at: now,
            updated_at: now,
        }
    }
}
