//! Fluent Kubernetes Builder API
//!
//! Provides a high-level, fluent API for building and managing Kubernetes resources.
//! All resource names are automatically normalized using `name_fix_kubernetes` for RFC 1123 compliance.

use super::kubernetes_manager::KubernetesManager;
use super::KubernetesError;
use herolib_core::text::name_fix_kubernetes;
use std::collections::HashMap;
use log;

/// Helper function to delete a pod and wait until it's really gone
async fn delete_pod_and_wait(km: &KubernetesManager, name: &str, max_wait_ms: u64) -> Result<(), KubernetesError> {
    // Try to delete
    let _ = km.pod_delete(name).await;
    
    // Wait until the pod is actually gone (max 5 seconds)
    let mut elapsed = 0u64;
    loop {
        tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
        elapsed += 100;
        
        // Check if pod still exists
        let pods = km.pods_list().await?;
        let pod_exists = pods.iter().any(|p| {
            p.metadata.name.as_ref().map(|n| n == name).unwrap_or(false)
        });
        
        if !pod_exists {
            return Ok(());
        }
        
        if elapsed >= max_wait_ms {
            return Ok(()); // Give up waiting
        }
    }
}

#[allow(dead_code)]
/// Helper function to delete a resource and wait (generic for other resource types)
async fn delete_and_wait(
    km: &KubernetesManager,
    name: &str,
    resource_type: &str,
    max_wait_ms: u64,
) -> Result<(), KubernetesError> {
    match resource_type {
        "pod" => delete_pod_and_wait(km, name, max_wait_ms).await,
        "service" => {
            let _ = km.service_delete(name).await;
            tokio::time::sleep(tokio::time::Duration::from_millis(300)).await;
            Ok(())
        },
        "configmap" => {
            let _ = km.configmap_delete(name).await;
            tokio::time::sleep(tokio::time::Duration::from_millis(200)).await;
            Ok(())
        },
        "secret" => {
            let _ = km.secret_delete(name).await;
            tokio::time::sleep(tokio::time::Duration::from_millis(200)).await;
            Ok(())
        },
        "deployment" => {
            let _ = km.deployment_delete(name).await;
            tokio::time::sleep(tokio::time::Duration::from_millis(300)).await;
            Ok(())
        },
        _ => Ok(()),
    }
}

/// Global Kubernetes context builder
pub struct KubernetesContext;

impl KubernetesContext {
    /// Create a new Kubernetes context
    pub async fn new() -> Result<Self, KubernetesError> {
        Ok(KubernetesContext)
    }

    /// Reset the Kubernetes cluster (delete all namespaces except core system namespaces)
    ///
    /// This operation will delete all user-created namespaces while protecting core
    /// Kubernetes system namespaces (default, kube-system, kube-public, kube-node-lease, kube-apiserver)
    pub async fn reset(&mut self) -> Result<(), KubernetesError> {
        // Get a temporary manager to list and reset namespaces
        let km = KubernetesManager::new("default").await?;
        
        // Get list of all namespaces
        let namespaces = km.namespaces_list().await?;
        
        // Core namespaces that should be protected
        let protected = [
            "default",
            "kube-system",
            "kube-public",
            "kube-node-lease",
            "kube-apiserver",
        ];
        
        // Reset only non-protected namespaces
        for ns in namespaces {
            if let Some(name) = &ns.metadata.name {
                if !protected.contains(&name.as_str()) {
                    log::info!("Resetting non-core namespace: {}", name);
                    km.namespace_reset(name).await.ok(); // Ignore errors for individual namespaces
                }
            }
        }
        
        log::info!("Kubernetes cluster reset completed (protected namespaces: {})", protected.join(", "));
        Ok(())
    }

    /// Get markdown representation of cluster state
    /// Shows all namespaces and their resources in a hierarchical format
    pub async fn md(&self) -> Result<String, KubernetesError> {
        let km = KubernetesManager::new("default").await?;
        let namespaces = km.namespaces_list().await?;
        
        let mut md = String::from("# Kubernetes Cluster Overview\n\n");
        
        if namespaces.is_empty() {
            md.push_str("No namespaces found.\n");
            return Ok(md);
        }
        
        md.push_str("## Namespaces\n\n");
        
        for ns in namespaces {
            if let Some(ns_name) = &ns.metadata.name {
                md.push_str(&format!("### {}\n\n", ns_name));
                
                // Get resources for this namespace
                let km_ns = KubernetesManager::new(ns_name).await?;
                
                // Get all resource types
                let pods = km_ns.pods_list().await.unwrap_or_default();
                let services = km_ns.services_list().await.unwrap_or_default();
                let deployments = km_ns.deployments_list().await.unwrap_or_default();
                let configmaps = km_ns.configmaps_list().await.unwrap_or_default();
                let secrets = km_ns.secrets_list().await.unwrap_or_default();
                
                // Pods section
                md.push_str("#### Pods\n");
                if pods.is_empty() {
                    md.push_str("- *(none)*\n");
                } else {
                    for pod in &pods {
                        if let Some(pod_name) = &pod.metadata.name {
                            let status = pod.status.as_ref()
                                .and_then(|s| s.phase.as_ref())
                                .map(|p| p.as_str())
                                .unwrap_or("Unknown");
                            md.push_str(&format!("- **{}** `{}`\n", pod_name, status));
                        }
                    }
                }
                md.push_str("\n");
                
                // Services section
                md.push_str("#### Services\n");
                if services.is_empty() {
                    md.push_str("- *(none)*\n");
                } else {
                    for svc in &services {
                        if let Some(svc_name) = &svc.metadata.name {
                            let svc_type = svc.spec.as_ref()
                                .and_then(|s| s.type_.as_ref())
                                .map(|t| t.as_str())
                                .unwrap_or("ClusterIP");
                            md.push_str(&format!("- **{}** `{}`\n", svc_name, svc_type));
                        }
                    }
                }
                md.push_str("\n");
                
                // Deployments section
                md.push_str("#### Deployments\n");
                if deployments.is_empty() {
                    md.push_str("- *(none)*\n");
                } else {
                    for deploy in &deployments {
                        if let Some(deploy_name) = &deploy.metadata.name {
                            let replicas = deploy.spec.as_ref()
                                .and_then(|s| s.replicas)
                                .unwrap_or(0);
                            let ready_replicas = deploy.status.as_ref()
                                .and_then(|s| s.ready_replicas)
                                .unwrap_or(0);
                            md.push_str(&format!("- **{}** ({}/{})\n", deploy_name, ready_replicas, replicas));
                        }
                    }
                }
                md.push_str("\n");
                
                // ConfigMaps section
                md.push_str("#### ConfigMaps\n");
                if configmaps.is_empty() {
                    md.push_str("- *(none)*\n");
                } else {
                    for cm in &configmaps {
                        if let Some(cm_name) = &cm.metadata.name {
                            let key_count = cm.data.as_ref().map(|d| d.len()).unwrap_or(0);
                            md.push_str(&format!("- **{}** ({} keys)\n", cm_name, key_count));
                        }
                    }
                }
                md.push_str("\n");
                
                // Secrets section
                md.push_str("#### Secrets\n");
                if secrets.is_empty() {
                    md.push_str("- *(none)*\n");
                } else {
                    for secret in &secrets {
                        if let Some(secret_name) = &secret.metadata.name {
                            let secret_type = secret.type_.as_ref()
                                .map(|t| t.as_str())
                                .unwrap_or("Opaque");
                            let data_count = secret.data.as_ref().map(|d| d.len()).unwrap_or(0);
                            md.push_str(&format!("- **{}** `{}` ({} keys)\n", secret_name, secret_type, data_count));
                        }
                    }
                }
                md.push_str("\n");
            }
        }
        
        Ok(md)
    }

    /// List all namespaces
    pub async fn ns_list(&self) -> Result<Vec<String>, KubernetesError> {
        let km = KubernetesManager::new("default").await?;
        let namespaces = km.namespaces_list().await?;
        
        Ok(namespaces
            .into_iter()
            .filter_map(|ns| ns.metadata.name)
            .collect())
    }

    /// Delete a namespace (with automatic name fixing)
    pub async fn ns_delete(&self, name: &str) -> Result<(), KubernetesError> {
        let fixed_name = name_fix_kubernetes(name);
        let km = KubernetesManager::new("default").await?;
        km.namespace_delete(&fixed_name).await
    }

    /// Get or create a namespace
    pub async fn namespace(&self, name: &str) -> Result<NamespaceBuilder, KubernetesError> {
        let fixed_name = name_fix_kubernetes(name);
        let km = KubernetesManager::new(&fixed_name).await?;
        
        // Try to create the namespace (idempotent)
        km.namespace_create(&fixed_name).await.ok();
        
        Ok(NamespaceBuilder {
            name: fixed_name,
            km,
        })
    }
}

/// Namespace builder for fluent API
#[derive(Clone)]
pub struct NamespaceBuilder {
    pub name: String,
    pub km: KubernetesManager,
}

impl NamespaceBuilder {
    /// Reset the namespace (delete and recreate)
    pub async fn reset(&self) -> Result<(), KubernetesError> {
        self.km.namespace_reset(&self.name).await
    }

    /// Get markdown representation of namespace
    /// Shows all resources with detailed information
    pub async fn md(&self) -> Result<String, KubernetesError> {
        let pods = self.km.pods_list().await?;
        let services = self.km.services_list().await?;
        let deployments = self.km.deployments_list().await?;
        let configmaps = self.km.configmaps_list().await?;
        let secrets = self.km.secrets_list().await?;
        
        let mut md = format!("# Namespace: {}\n\n", self.name);
        
        // Summary section
        md.push_str("## Summary\n\n");
        md.push_str(&format!("| Resource Type | Count |\n"));
        md.push_str(&format!("|---|---|\n"));
        md.push_str(&format!("| Pods | {} |\n", pods.len()));
        md.push_str(&format!("| Services | {} |\n", services.len()));
        md.push_str(&format!("| Deployments | {} |\n", deployments.len()));
        md.push_str(&format!("| ConfigMaps | {} |\n", configmaps.len()));
        md.push_str(&format!("| Secrets | {} |\n", secrets.len()));
        md.push_str("\n");
        
        // Pods section
        md.push_str("## Pods\n\n");
        if pods.is_empty() {
            md.push_str("*(no pods)*\n");
        } else {
            md.push_str("| Name | Status | Restarts | Age |\n");
            md.push_str("|---|---|---|---|\n");
            for pod in pods {
                if let Some(pod_name) = &pod.metadata.name {
                    let status = pod.status.as_ref()
                        .and_then(|s| s.phase.as_ref())
                        .map(|p| p.as_str())
                        .unwrap_or("Unknown");
                    
                    let restart_count = pod.status.as_ref()
                        .and_then(|s| s.container_statuses.as_ref())
                        .map(|cs| cs.iter().map(|c| c.restart_count).sum::<i32>())
                        .unwrap_or(0);
                    
                    let created = pod.metadata.creation_timestamp.as_ref()
                        .map(|t| t.0.format("%Y-%m-%d %H:%M:%S").to_string())
                        .unwrap_or_else(|| "Unknown".to_string());
                    
                    md.push_str(&format!("| {} | {} | {} | {} |\n", pod_name, status, restart_count, created));
                }
            }
        }
        md.push_str("\n");
        
        // Services section
        md.push_str("## Services\n\n");
        if services.is_empty() {
            md.push_str("*(no services)*\n");
        } else {
            md.push_str("| Name | Type | Cluster IP | Ports |\n");
            md.push_str("|---|---|---|---|\n");
            for svc in services {
                if let Some(svc_name) = &svc.metadata.name {
                    let svc_type = svc.spec.as_ref()
                        .and_then(|s| s.type_.as_ref())
                        .map(|t| t.as_str())
                        .unwrap_or("ClusterIP");
                    
                    let cluster_ip = svc.spec.as_ref()
                        .and_then(|s| s.cluster_ip.as_ref())
                        .map(|ip| ip.as_str())
                        .unwrap_or("None");
                    
                    let ports = svc.spec.as_ref()
                        .and_then(|s| s.ports.as_ref())
                        .map(|ps| ps.iter()
                            .filter_map(|p| {
                                let port = p.port.to_string();
                                let target_port = p.target_port.as_ref()
                                    .map(|tp| {
                                        match tp {
                                            k8s_openapi::apimachinery::pkg::util::intstr::IntOrString::Int(i) => format!("→{}", i),
                                            k8s_openapi::apimachinery::pkg::util::intstr::IntOrString::String(s) => format!("→{}", s),
                                        }
                                    })
                                    .unwrap_or_default();
                                if target_port.is_empty() {
                                    Some(port)
                                } else {
                                    Some(format!("{}{}", port, target_port))
                                }
                            })
                            .collect::<Vec<_>>()
                            .join(", "))
                        .unwrap_or_else(|| "None".to_string());
                    
                    md.push_str(&format!("| {} | {} | {} | {} |\n", svc_name, svc_type, cluster_ip, ports));
                }
            }
        }
        md.push_str("\n");
        
        // Deployments section
        md.push_str("## Deployments\n\n");
        if deployments.is_empty() {
            md.push_str("*(no deployments)*\n");
        } else {
            md.push_str("| Name | Replicas | Ready | Updated | Available |\n");
            md.push_str("|---|---|---|---|---|\n");
            for deploy in deployments {
                if let Some(deploy_name) = &deploy.metadata.name {
                    let replicas = deploy.spec.as_ref()
                        .and_then(|s| s.replicas)
                        .unwrap_or(0);
                    let ready_replicas = deploy.status.as_ref()
                        .and_then(|s| s.ready_replicas)
                        .unwrap_or(0);
                    let updated_replicas = deploy.status.as_ref()
                        .and_then(|s| s.updated_replicas)
                        .unwrap_or(0);
                    let available_replicas = deploy.status.as_ref()
                        .and_then(|s| s.available_replicas)
                        .unwrap_or(0);
                    
                    md.push_str(&format!("| {} | {} | {}/{} | {} | {} |\n", 
                        deploy_name, replicas, ready_replicas, replicas, updated_replicas, available_replicas));
                }
            }
        }
        md.push_str("\n");
        
        // ConfigMaps section
        md.push_str("## ConfigMaps\n\n");
        if configmaps.is_empty() {
            md.push_str("*(no configmaps)*\n");
        } else {
            md.push_str("| Name | Keys |\n");
            md.push_str("|---|---|\n");
            for cm in configmaps {
                if let Some(cm_name) = &cm.metadata.name {
                    let keys = cm.data.as_ref()
                        .map(|d| d.keys().map(|k| k.as_str()).collect::<Vec<_>>().join(", "))
                        .unwrap_or_else(|| "None".to_string());
                    md.push_str(&format!("| {} | {} |\n", cm_name, keys));
                }
            }
        }
        md.push_str("\n");
        
        // Secrets section
        md.push_str("## Secrets\n\n");
        if secrets.is_empty() {
            md.push_str("*(no secrets)*\n");
        } else {
            md.push_str("| Name | Type | Keys |\n");
            md.push_str("|---|---|---|\n");
            for secret in secrets {
                if let Some(secret_name) = &secret.metadata.name {
                    let secret_type = secret.type_.as_ref()
                        .map(|t| t.as_str())
                        .unwrap_or("Opaque");
                    let keys = secret.data.as_ref()
                        .map(|d| d.keys().map(|k| k.as_str()).collect::<Vec<_>>().join(", "))
                        .unwrap_or_else(|| "None".to_string());
                    md.push_str(&format!("| {} | {} | {} |\n", secret_name, secret_type, keys));
                }
            }
        }
        md.push_str("\n");
        
        Ok(md)
    }

    /// List pods in namespace
    pub async fn pods_list(&self) -> Result<Vec<String>, KubernetesError> {
        let pods = self.km.pods_list().await?;
        Ok(pods
            .into_iter()
            .filter_map(|pod| pod.metadata.name)
            .collect())
    }

    /// List deployments in namespace
    pub async fn deployments_list(&self) -> Result<Vec<String>, KubernetesError> {
        let deployments = self.km.deployments_list().await?;
        Ok(deployments
            .into_iter()
            .filter_map(|dep| dep.metadata.name)
            .collect())
    }

    /// List services in namespace
    pub async fn services_list(&self) -> Result<Vec<String>, KubernetesError> {
        let services = self.km.services_list().await?;
        Ok(services
            .into_iter()
            .filter_map(|svc| svc.metadata.name)
            .collect())
    }

    /// List secrets in namespace
    pub async fn secrets_list(&self) -> Result<Vec<String>, KubernetesError> {
        let secrets = self.km.secrets_list().await?;
        Ok(secrets
            .into_iter()
            .filter_map(|secret| secret.metadata.name)
            .collect())
    }

    /// List configmaps in namespace
    pub async fn configmaps_list(&self) -> Result<Vec<String>, KubernetesError> {
        let configmaps = self.km.configmaps_list().await?;
        Ok(configmaps
            .into_iter()
            .filter_map(|cm| cm.metadata.name)
            .collect())
    }

    /// Create or get a ConfigMap
    pub fn configmap(&self, name: &str) -> ConfigMapBuilder {
        let fixed_name = name_fix_kubernetes(name);
        ConfigMapBuilder {
            name: fixed_name,
            data: HashMap::new(),
            km: self.km.clone(),
        }
    }

    /// Create or get a Secret
    pub fn secret(&self, name: &str) -> SecretBuilder {
        let fixed_name = name_fix_kubernetes(name);
        SecretBuilder {
            name: fixed_name,
            data: HashMap::new(),
            km: self.km.clone(),
        }
    }

    /// Create or get a Pod
    pub fn pod(&self, name: &str) -> PodBuilder {
        let fixed_name = name_fix_kubernetes(name);
        PodBuilder {
            name: fixed_name,
            km: self.km.clone(),
            image: String::new(),
            env: HashMap::new(),
            labels: HashMap::new(),
            ports: Vec::new(),
        }
    }

    /// Create or get a Service
    pub fn service(&self, name: &str) -> ServiceBuilder {
        let fixed_name = name_fix_kubernetes(name);
        ServiceBuilder {
            name: fixed_name,
            km: self.km.clone(),
            selector: HashMap::new(),
            port: 80,
            target_port: None,
        }
    }

    /// Create or get a Deployment
    pub fn deployment(&self, name: &str) -> DeploymentBuilder {
        let fixed_name = name_fix_kubernetes(name);
        DeploymentBuilder {
            name: fixed_name,
            km: self.km.clone(),
            image: String::new(),
            replicas: 1,
            env: HashMap::new(),
            labels: HashMap::new(),
            ports: Vec::new(),
        }
    }
}

/// ConfigMap builder
#[derive(Clone)]
pub struct ConfigMapBuilder {
    pub name: String,
    pub data: HashMap<String, String>,
    pub km: KubernetesManager,
}

impl ConfigMapBuilder {
    /// Set a key-value pair
    pub fn set(mut self, key: &str, value: &str) -> Self {
        self.data.insert(key.to_string(), value.to_string());
        self
    }

    /// Get a value
    pub fn get(&self, key: &str) -> Result<String, KubernetesError> {
        self.data
            .get(key)
            .cloned()
            .ok_or_else(|| KubernetesError::OperationError("Key not found".to_string()))
    }

      /// Create the ConfigMap in the Kubernetes cluster (idempotent - replaces if exists)
      pub async fn apply(&self) -> Result<(), KubernetesError> {
          // Delete the ConfigMap if it exists to ensure clean state
          let _ = self.km.configmap_delete(&self.name).await;
          
          // Wait for deletion to propagate
          tokio::time::sleep(tokio::time::Duration::from_millis(200)).await;
          
          // Now create it with the new config
          self.km.configmap_create(&self.name, self.data.clone()).await?;
          Ok(())
      }
     
     /// Alias for apply() - `do_()` is used in Rhai since `do` is a reserved keyword
     pub async fn do_(&self) -> Result<(), KubernetesError> {
         self.apply().await
     }
}

/// Secret builder
#[derive(Clone)]
pub struct SecretBuilder {
    pub name: String,
    pub data: HashMap<String, String>,
    pub km: KubernetesManager,
}

impl SecretBuilder {
    /// Set a key-value pair
    pub fn set(mut self, key: &str, value: &str) -> Self {
        self.data.insert(key.to_string(), value.to_string());
        self
    }

    /// Get a value
    pub fn get(&self, key: &str) -> Result<String, KubernetesError> {
        self.data
            .get(key)
            .cloned()
            .ok_or_else(|| KubernetesError::OperationError("Key not found".to_string()))
    }

      /// Create the Secret in the Kubernetes cluster (idempotent - replaces if exists)
      pub async fn apply(&self) -> Result<(), KubernetesError> {
          // Delete the Secret if it exists to ensure clean state
          let _ = self.km.secret_delete(&self.name).await;
          
          // Wait for deletion to propagate
          tokio::time::sleep(tokio::time::Duration::from_millis(200)).await;
          
          // Now create it with the new config
          self.km.secret_create(&self.name, self.data.clone(), Some("Opaque")).await?;
          Ok(())
      }

     /// Alias for apply() - `do_()` is used in Rhai since `do` is a reserved keyword
     pub async fn do_(&self) -> Result<(), KubernetesError> {
         self.apply().await
     }
}

/// Pod builder
#[derive(Clone)]
pub struct PodBuilder {
    pub name: String,
    pub km: KubernetesManager,
    pub image: String,
    pub env: HashMap<String, String>,
    pub labels: HashMap<String, String>,
    pub ports: Vec<u16>,
}

impl PodBuilder {
    /// Set the image
    pub fn image(mut self, image: &str) -> Self {
        self.image = image.to_string();
        self
    }

     /// Set environment variables from a HashMap
     pub fn env_map(mut self, env: HashMap<String, String>) -> Self {
         self.env.extend(env);
         self
     }

     /// Set a single environment variable
     pub fn env(mut self, key: &str, value: &str) -> Self {
         self.env.insert(key.to_string(), value.to_string());
         self
     }

    /// Add a label
    pub fn label(mut self, key: &str, value: &str) -> Self {
        self.labels.insert(key.to_string(), value.to_string());
        self
    }

    /// Add a port
    pub fn port(mut self, port: u16) -> Self {
        self.ports.push(port);
        self
    }

     /// **NOT YET IMPLEMENTED** - Set memory (requested, limit in MB)
     /// This feature is planned for a future release.
     #[deprecated(since = "0.2.0", note = "Memory limits not yet implemented in Rust fluent API")]
     pub fn memory(self, _requested: u32, _limit: u32) -> Self {
         self
     }

     /// **NOT YET IMPLEMENTED** - Set CPU (requested, limit in milli-cores)
     /// This feature is planned for a future release.
     #[deprecated(since = "0.2.0", note = "CPU limits not yet implemented in Rust fluent API")]
     pub fn cpu(self, _requested: u32, _limit: u32) -> Self {
         self
     }

     /// **NOT YET IMPLEMENTED** - Add readiness HTTP probe
     /// This feature is planned for a future release.
     #[deprecated(since = "0.2.0", note = "Readiness HTTP probe not yet implemented in Rust fluent API")]
     pub fn readiness_http(self, _path: &str, _port: u16) -> Self {
         self
     }

     /// **NOT YET IMPLEMENTED** - Add liveness HTTP probe
     /// This feature is planned for a future release.
     #[deprecated(since = "0.2.0", note = "Liveness HTTP probe not yet implemented in Rust fluent API")]
     pub fn liveness_http(self, _path: &str, _port: u16) -> HealthCheckBuilder {
         HealthCheckBuilder { pod: self }
     }

     /// **NOT YET IMPLEMENTED** - Add readiness TCP probe
     /// This feature is planned for a future release.
     #[deprecated(since = "0.2.0", note = "Readiness TCP probe not yet implemented in Rust fluent API")]
     pub fn readiness_tcp(self, _port: u16) -> Self {
         self
     }

     /// **NOT YET IMPLEMENTED** - Add liveness TCP probe
     /// This feature is planned for a future release.
     #[deprecated(since = "0.2.0", note = "Liveness TCP probe not yet implemented in Rust fluent API")]
     pub fn liveness_tcp(self, _port: u16) -> HealthCheckBuilder {
         HealthCheckBuilder { pod: self }
     }

     /// **NOT YET IMPLEMENTED** - Set restart policy
     /// This feature is planned for a future release.
     #[deprecated(since = "0.2.0", note = "Restart policy not yet implemented in Rust fluent API")]
     pub fn restart(self, _policy: &str) -> Self {
         self
     }

     /// **NOT YET IMPLEMENTED** - Import environment variables from ConfigMap
     /// This feature is planned for a future release.
     #[deprecated(since = "0.2.0", note = "env_from_configmap not yet implemented in Rust fluent API")]
     pub fn env_from_configmap(self, _configmap: &str) -> Self {
         self
     }

     /// **NOT YET IMPLEMENTED** - Import environment variables from Secret
     /// This feature is planned for a future release.
     #[deprecated(since = "0.2.0", note = "env_from_secret not yet implemented in Rust fluent API")]
     pub fn env_from_secret(self, _secret: &str) -> Self {
         self
     }

      /// Create the Pod in the Kubernetes cluster (idempotent - replaces if exists)
      pub async fn apply(&self) -> Result<(), KubernetesError> {
          // Delete the Pod if it exists and wait until it's gone
          let _ = delete_pod_and_wait(&self.km, &self.name, 5000).await;
          
          // Now create it with the new config
          self.km
              .pod_create(&self.name, &self.image, Some(self.labels.clone()), Some(self.env.clone()))
              .await?;
          Ok(())
      }

     /// Alias for apply() - `do_()` is used in Rhai since `do` is a reserved keyword
     pub async fn do_(&self) -> Result<(), KubernetesError> {
         self.apply().await
     }
}

/// Health check builder for liveness/readiness probes
#[derive(Clone)]
pub struct HealthCheckBuilder {
    pub pod: PodBuilder,
}

impl HealthCheckBuilder {
     /// **NOT YET IMPLEMENTED** - Set initial delay in seconds
     /// This feature is planned for a future release.
     #[deprecated(since = "0.2.0", note = "initial_delay not yet implemented in Rust fluent API")]
     pub fn initial_delay(self, _delay: u32) -> Self {
         self
     }

     /// **NOT YET IMPLEMENTED** - Set probe period in seconds
     /// This feature is planned for a future release.
     #[deprecated(since = "0.2.0", note = "period not yet implemented in Rust fluent API")]
     pub fn period(self, _period: u32) -> Self {
         self
     }

     /// **NOT YET IMPLEMENTED** - Set failure threshold
     /// This feature is planned for a future release.
     #[deprecated(since = "0.2.0", note = "failure_threshold not yet implemented in Rust fluent API")]
     pub fn failure_threshold(self, _threshold: u32) -> PodBuilder {
         self.pod
     }
 }

/// Service builder
#[derive(Clone)]
pub struct ServiceBuilder {
    pub name: String,
    pub km: KubernetesManager,
    pub selector: HashMap<String, String>,
    pub port: u16,
    pub target_port: Option<u16>,
}

impl ServiceBuilder {
    /// Set service selector
    pub fn selector(mut self, key: &str, value: &str) -> Self {
        self.selector.insert(key.to_string(), value.to_string());
        self
    }

     /// **NOT YET IMPLEMENTED** - Add a label to the service
     /// This feature is planned for a future release.
     #[deprecated(since = "0.2.0", note = "Service labels not yet implemented in Rust fluent API")]
     pub fn label(self, _key: &str, _value: &str) -> Self {
         self
     }

     /// Expose a port
     pub fn expose(mut self, port: u16) -> Self {
         self.port = port;
         self
     }

     /// Set target container port
     pub fn to_container(mut self, port: u16) -> Self {
         self.target_port = Some(port);
         self
     }

     /// Set target port with alias
     pub fn to(mut self, port: u16) -> Self {
         self.target_port = Some(port);
         self
     }

     /// **NOT YET IMPLEMENTED** - Set port to UDP
     /// Currently only TCP is supported. This feature is planned for a future release.
     #[deprecated(since = "0.2.0", note = "UDP protocol not yet implemented in Rust fluent API")]
     pub fn udp(self) -> Self {
         self
     }

     /// **NOT YET IMPLEMENTED** - Set NodePort service type
     /// This feature is planned for a future release.
     /// See `service_create_lb()` in KubernetesManager for alternative load balancer support.
     #[deprecated(since = "0.2.0", note = "NodePort not yet implemented in Rust fluent API")]
     pub fn nodeport(self) -> Self {
         self
     }

     /// **NOT YET IMPLEMENTED** - Set Headless service type (ClusterIP: None)
     /// This feature is planned for a future release.
     #[deprecated(since = "0.2.0", note = "Headless service not yet implemented in Rust fluent API")]
     pub fn headless(self) -> Self {
         self
     }

     /// **NOT YET IMPLEMENTED** - Set service type
     /// This feature is planned for a future release.
     #[deprecated(since = "0.2.0", note = "Service type not yet implemented in Rust fluent API")]
     pub fn type_(self, _service_type: &str) -> Self {
         self
     }

     /// **NOT YET IMPLEMENTED** - Specify node port for NodePort services
     /// This feature is planned for a future release.
     #[deprecated(since = "0.2.0", note = "via_node not yet implemented in Rust fluent API")]
     pub fn via_node(self, _node_port: &str) -> Self {
         self
     }

      /// Create the Service in the Kubernetes cluster (idempotent - replaces if exists)
      pub async fn apply(&self) -> Result<(), KubernetesError> {
          // Delete the Service if it exists to ensure clean state
          let _ = self.km.service_delete(&self.name).await;
          
          // Wait for deletion to propagate
          tokio::time::sleep(tokio::time::Duration::from_millis(200)).await;
          
          // Now create it with the new config
          self.km
              .service_create(
                  &self.name,
                  self.selector.clone(),
                  self.port as i32,
                  self.target_port.map(|p| p as i32),
              )
              .await?;
          Ok(())
      }

      /// Alias for apply() - `do_()` is used in Rhai since `do` is a reserved keyword
      pub async fn do_(&self) -> Result<(), KubernetesError> {
          self.apply().await
      }
}

/// Deployment builder
#[derive(Clone)]
pub struct DeploymentBuilder {
    pub name: String,
    pub km: KubernetesManager,
    pub image: String,
    pub replicas: i32,
    pub env: HashMap<String, String>,
    pub labels: HashMap<String, String>,
    pub ports: Vec<u16>,
}

impl DeploymentBuilder {
    /// Set the image
    pub fn image(mut self, image: &str) -> Self {
        self.image = image.to_string();
        self
    }

    /// Set the number of replicas
    pub fn replicas(mut self, replicas: i32) -> Self {
        self.replicas = replicas;
        self
    }

    /// Set a single environment variable
    pub fn env(mut self, key: &str, value: &str) -> Self {
        self.env.insert(key.to_string(), value.to_string());
        self
    }

    /// Set environment variables from a HashMap
    pub fn env_map(mut self, env: HashMap<String, String>) -> Self {
        self.env.extend(env);
        self
    }

    /// Add a label
    pub fn label(mut self, key: &str, value: &str) -> Self {
        self.labels.insert(key.to_string(), value.to_string());
        self
    }

    /// Add a port
    pub fn port(mut self, port: u16) -> Self {
        self.ports.push(port);
        self
    }

    /// Create the Deployment in the Kubernetes cluster (idempotent - replaces if exists)
    pub async fn apply(&self) -> Result<(), KubernetesError> {
        // Delete the Deployment if it exists to ensure clean state
        let _ = self.km.deployment_delete(&self.name).await;
        
        // Wait for deletion to propagate
        tokio::time::sleep(tokio::time::Duration::from_millis(200)).await;
        
        // Now create it with the new config
        self.km
            .deployment_create(
                &self.name,
                &self.image,
                self.replicas,
                Some(self.labels.clone()),
                Some(self.env.clone()),
            )
            .await?;
        Ok(())
    }

    /// Alias for apply() - `do_()` is used in Rhai since `do` is a reserved keyword
    pub async fn do_(&self) -> Result<(), KubernetesError> {
        self.apply().await
    }
}
