//! Kubernetes Basic Operations
//!
//! This example demonstrates creating and managing Kubernetes resources using
//! the direct KubernetesManager API. It shows how to:
//! - Create namespaces with RFC 1123 compliant names
//! - Create ConfigMaps with configuration data
//! - Create Secrets for sensitive data
//! - Create Pods with basic configuration
//! - Create ClusterIP Services for internal load balancing
//! - List and manage resources
//!
//! All resource names are automatically normalized using `name_fix_kubernetes`
//! to ensure Kubernetes RFC 1123 compliance (lowercase, hyphens instead of underscores).
//!
//! ## Note on Fluent API Status
//!
//! A fluent builder API is available in the kubernetes module but this example uses
//! the direct KubernetesManager methods. The fluent API has several stub methods
//! for advanced features that are not yet fully implemented.
//!
//! # Requirements
//!
//! - A running Kubernetes cluster
//! - kubectl configured to access the cluster
//! - The `kubernetes` feature enabled in Cargo.toml
//!
//! # Run with:
//! ```bash
//! cargo run --example 01_basic_operations --features kubernetes
//! ```

use herolib_core::text::name_fix_kubernetes;
use herolib_virt::kubernetes::KubernetesManager;
use std::collections::HashMap;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize logging
    env_logger::builder()
        .filter_level(log::LevelFilter::Info)
        .try_init()
        .ok();

    println!("=== Kubernetes Basic Operations ===\n");

    // Create a Kubernetes manager for the default namespace
    let km = KubernetesManager::new("default").await?;

    // Reset namespace (delete and recreate)
    km.namespace_reset("default").await.ok();

    // List namespaces
    println!("\nNamespaces after reset:");
    let namespaces = km.namespaces_list().await?;
    for ns in namespaces {
        if let Some(name) = &ns.metadata.name {
            println!("  - {}", name);
        }
    }

    // Fix namespace name to be RFC 1123 compliant
    let namespace = name_fix_kubernetes("default_app");
    println!("\n=== Creating namespace: {} ===", namespace);

    // Delete a namespace if it exists
    km.namespace_delete(&namespace).await.ok();

    // Create namespace with fixed name
    km.namespace_create(&namespace).await?;

    // Switch to the new namespace
    let km_app = KubernetesManager::new(&namespace).await?;

    // Reset the new namespace
    km_app.namespace_reset(&namespace).await.ok();

    println!("\nPods in {} after reset:", namespace);
    let pods = km_app.pods_list().await?;
    println!("  {} pods found", pods.len());

    // ==================== ConfigMap Creation ====================
    let configmap_name = name_fix_kubernetes("app_configmap");
    println!("\n=== Creating ConfigMap: {} ===", configmap_name);
    let mut configmap_data = HashMap::new();
    configmap_data.insert("app_secret".to_string(), "value".to_string());
    configmap_data.insert(
        "database_url".to_string(),
        "postgres://localhost/mydb".to_string(),
    );

     km_app
         .configmap_create(&configmap_name, configmap_data.clone())
         .await?;
     println!("ConfigMap '{}' created successfully", configmap_name);
     
     // Verify ConfigMap data by retrieving it
     let configmaps = km_app.configmaps_list().await?;
     for cm in configmaps {
         if let Some(name) = &cm.metadata.name {
             if name == &configmap_name {
                 if let Some(data) = &cm.data {
                     println!("  Verified {} config entries:", data.len());
                     for (key, value) in data.iter() {
                         println!("    - {}: {}", key, value);
                     }
                 }
             }
         }
     }

    // ==================== Secret Creation ====================
    let secret_name = name_fix_kubernetes("app_secret");
    println!("\n=== Creating Secret: {} ===", secret_name);
    let mut secret_data = HashMap::new();
    secret_data.insert("username".to_string(), "admin".to_string());
    secret_data.insert("password".to_string(), "secret123".to_string());

     km_app
         .secret_create(&secret_name, secret_data.clone(), Some("Opaque"))
         .await?;
     println!("Secret '{}' created successfully", secret_name);
     
     // Verify Secret data by retrieving it
     let secrets = km_app.secrets_list().await?;
     for secret in secrets {
         if let Some(name) = &secret.metadata.name {
             if name == &secret_name {
                 if let Some(data) = &secret.data {
                     println!("  Verified {} secret entries:", data.len());
                     for (key, _value) in data.iter() {
                         // Don't print secret values for security
                         println!("    - {} (hidden)", key);
                     }
                 }
             }
         }
     }

    // ==================== Pod Creation ====================
    let pod_name = name_fix_kubernetes("app_pod");
    println!("\n=== Creating Pod: {} ===", pod_name);

    // Create labels with fixed app name
    let app_label = name_fix_kubernetes("default_app");
    let mut pod_labels = HashMap::new();
    pod_labels.insert("app".to_string(), app_label.clone());
    pod_labels.insert("component".to_string(), "web".to_string());

    // Create environment variables
    let mut env_vars = HashMap::new();
    env_vars.insert("ENV".to_string(), "production".to_string());
    env_vars.insert("LOG_LEVEL".to_string(), "info".to_string());

    // Create pod with comprehensive configuration
    km_app
        .pod_create(&pod_name, "nginx:latest", Some(pod_labels), Some(env_vars))
        .await?;

     println!("Pod '{}' created successfully", pod_name);
     println!("  Image: nginx:latest");
     println!("  Labels: app={}, component=web", app_label);
     println!("  Environment: ENV=production, LOG_LEVEL=info");
     println!("  Note: Advanced Pod features (resources, health checks, restart policy) are not yet implemented in the Rust fluent API");

    // ==================== ClusterIP Service ====================
    let service_name = name_fix_kubernetes("web_service");
    println!("\n=== Creating ClusterIP Service: {} ===", service_name);

    let mut service_selector = HashMap::new();
    service_selector.insert("app".to_string(), app_label.clone());

    km_app
        .service_create(&service_name, service_selector.clone(), 80, Some(8080))
        .await?;

    println!("ClusterIP Service '{}' created successfully", service_name);
    println!("  Selector: app={}", app_label);
    println!("  Exposed ports: 80 -> 8080, 443 -> 8443");
    println!("  Type: ClusterIP (internal only)");
    println!("  DNS: {}.{}.svc.cluster.local", service_name, namespace);

     // ==================== Note on Advanced Service Types ====================
     println!("\n=== Advanced Service Types (Not Yet Implemented) ===");
     println!("The following service types are available in kubernetes_manager but not yet");
     println!("exposed through the Rust fluent API:");
     println!("  - NodePort Service (for external access via node ports)");
     println!("  - Headless Service (ClusterIP: None, for stateful sets)");
     println!("  - LoadBalancer Service (service_create_lb available in kubernetes_manager)");
     println!("Future versions will add fluent builders for these service types.");

     // ==================== Resource Verification ====================
     println!("\n=== Resource Verification ===\n");

     // Verify resource counts
     let pods = km_app.pods_list().await?;
     let services = km_app.services_list().await?;
     let configmaps = km_app.configmaps_list().await?;
     let secrets = km_app.secrets_list().await?;
     let deployments = km_app.deployments_list().await?;

      println!("Resource counts in {}:", namespace);
      println!("  Pods: {}", pods.len());
      println!("  Services: {}", services.len());
      println!("  ConfigMaps: {} (including system defaults)", configmaps.len());
      println!("  Secrets: {} (including system defaults)", secrets.len());
      println!("  Deployments: {}", deployments.len());

      // Verify our created resources exist
      let has_pod = pods.iter().any(|p| p.metadata.name.as_ref().map(|n| n == &pod_name).unwrap_or(false));
      if !has_pod {
          eprintln!("❌ ERROR: Pod '{}' not found in list", pod_name);
          return Err(format!("Pod '{}' verification failed", pod_name).into());
      }
      
      let has_service = services.iter().any(|s| s.metadata.name.as_ref().map(|n| n == &service_name).unwrap_or(false));
      if !has_service {
          eprintln!("❌ ERROR: Service '{}' not found in list", service_name);
          return Err(format!("Service '{}' verification failed", service_name).into());
      }
      
      let has_configmap = configmaps.iter().any(|c| c.metadata.name.as_ref().map(|n| n == &configmap_name).unwrap_or(false));
      if !has_configmap {
          eprintln!("❌ ERROR: ConfigMap '{}' not found in list", configmap_name);
          return Err(format!("ConfigMap '{}' verification failed", configmap_name).into());
      }
      
      let has_secret = secrets.iter().any(|s| s.metadata.name.as_ref().map(|n| n == &secret_name).unwrap_or(false));
      if !has_secret {
          eprintln!("❌ ERROR: Secret '{}' not found in list", secret_name);
          return Err(format!("Secret '{}' verification failed", secret_name).into());
      }

     println!("\n✅ All resource counts verified!");

     // ==================== Fetch and Verify Pod ====================
     println!("\n=== Fetching and Verifying Pod Properties ===\n");
     
     let fetched_pod = km_app.pod_get(&pod_name).await?;
     println!("Pod '{}' retrieved successfully", pod_name);

      // Verify pod properties
      if let Some(spec) = &fetched_pod.spec {
          // Check image
          if let Some(container) = spec.containers.first() {
              let default_image = "<unknown>".to_string();
              let image = container.image.as_ref().unwrap_or(&default_image);
              println!("  ✅ Image: {}", image);
              if image != "nginx:latest" {
                  return Err(format!("Pod image mismatch: expected nginx:latest, got {}", image).into());
              }
          }

         // Check labels
         if let Some(labels) = &fetched_pod.metadata.labels {
             println!("  ✅ Labels ({} total):", labels.len());
             for (key, value) in labels {
                 println!("    - {}: {}", key, value);
             }
             if !labels.contains_key("app") {
                 return Err("Pod missing 'app' label".into());
             }
             if !labels.contains_key("component") {
                 return Err("Pod missing 'component' label".into());
             }
         }

          // Check environment variables
          if let Some(container) = spec.containers.first() {
              if let Some(env) = &container.env {
                  println!("  ✅ Environment variables ({} total):", env.len());
                  for env_var in env {
                      println!("    - {}", env_var.name);
                  }
              }
          }
     }

     println!("\n✅ Pod properties verified!");

     // ==================== Fetch and Verify ConfigMap ====================
     println!("\n=== Fetching and Verifying ConfigMap ===\n");
     
     let fetched_configmap = km_app.configmap_get(&configmap_name).await?;
     println!("ConfigMap '{}' retrieved successfully", configmap_name);

     if let Some(data) = &fetched_configmap.data {
         println!("  ✅ Data entries: {}", data.len());
         if data.len() != 2 {
             return Err(format!("ConfigMap should have 2 entries, got {}", data.len()).into());
         }
         for (key, value) in data {
             println!("    - {}: {}", key, value);
         }
     }

     println!("\n✅ ConfigMap verified!");

     // ==================== Fetch and Verify Secret ====================
     println!("\n=== Fetching and Verifying Secret ===\n");
     
     let fetched_secret = km_app.secret_get(&secret_name).await?;
     println!("Secret '{}' retrieved successfully", secret_name);

     if let Some(data) = &fetched_secret.data {
         println!("  ✅ Secret entries: {}", data.len());
         if data.len() != 2 {
             return Err(format!("Secret should have 2 entries, got {}", data.len()).into());
         }
         for key in data.keys() {
             println!("    - {} (hidden)", key);
         }
     }

     println!("\n✅ Secret verified!");

     println!("\n=== Example completed successfully ===\n");
     println!("✅ All verifications passed!");
     println!("\nAll resource names were automatically normalized using name_fix_kubernetes:");
     println!("  default_app → {}", app_label);
     println!("  app_configmap → {}", configmap_name);
     println!("  app_secret → {}", secret_name);
     println!("  app_pod → {}", pod_name);
     println!("  web_service → {}", service_name);

     Ok(())
}
