//! Registry Build and Push Example
//!
//! This example demonstrates:
//! 1. Deploy a Docker Registry on Kubernetes
//! 2. Use BuilderConfig with Kubernetes execution to build a container image
//! 3. Push the built image to the registry
//! 4. Verify the image exists in the registry
//!
//! The key feature shown here is using the same `BuilderConfig` API for both
//! local and remote (Kubernetes) execution - just add `.kubernetes(namespace, pod)`.
//!
//! # Usage
//!
//! ```bash
//! cargo run --example 03_registry_build_and_push --features kubernetes
//! ```

use herolib_virt::buildah::BuildahContainer;
use herolib_virt::kubernetes::{BuildMachine, KubernetesManager, RegistryDeployerBuilder};

/// Helper function to print section headers
fn print_section(title: &str) {
    println!("\n=====================================");
    println!("  {}", title);
    println!("=====================================\n");
}

/// Helper function to print test results
fn print_test(test_num: usize, description: &str, passed: bool) {
    let status = if passed { "✓ PASS" } else { "✗ FAIL" };
    println!("Test {}: {} ... {}", test_num, description, status);
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    print_section("Registry Build and Push Example");

    println!("This example demonstrates building and pushing an image to a registry");
    println!("deployed on Kubernetes using the BuilderConfig fluent API.\n");

    // Track test results
    let mut tests_passed = 0;
    let mut tests_failed = 0;

    // Create Kubernetes manager
    let km = KubernetesManager::new("build-push").await?;
    println!("✓ Connected to Kubernetes cluster");
    println!("  Operating on namespace: {}\n", km.namespace());

    // Test 1: Create namespace
    print_section("Test 1: Create Namespace");
    km.namespace_create("build-push").await?;
    print_test(1, "Namespace creation", true);
    tests_passed += 1;

    // Test 2: Deploy registry
    print_section("Test 2: Deploy Docker Registry");
    let deployer = RegistryDeployerBuilder::new(km.clone(), "local-registry")
        .node_port(30500)
        .timeout_secs(120)
        .deploy()
        .await?;

    print_test(2, "Registry deployment", true);
    println!("  Registry: {}", deployer.connection_string());
    println!("  Image Prefix: {}", deployer.image_prefix());
    tests_passed += 1;
    println!();

    // Test 3: Create build machine (pod with buildah)
    print_section("Test 3: Provision Build Machine");
    let build_machine = BuildMachine::new("build-push", "builder");
    let handle = build_machine.provision().await?;
    print_test(3, "Build machine provisioned", true);
    println!("  Pod Name: {}", handle.pod_name());
    println!("  Namespace: {}", handle.namespace());
    tests_passed += 1;

    // Test 4: Build image using BuildahContainer with Kubernetes execution
    //
    // This is the key part - same API as local builds, just add .kubernetes()!
    //
    // Local build would be:
    //   BuildahContainer::new("myapp", "alpine:latest")
    //       .debug(true)
    //       .build()?;
    //
    // Kubernetes build is:
    //   BuildahContainer::new("myapp", "alpine:latest")
    //       .kubernetes(namespace, pod_name)
    //       .debug(true)
    //       .build()?;
    print_section("Test 4: Build Image with BuildahContainer");
    println!("Using BuildahContainer with Kubernetes execution target...\n");

    let builder = BuildahContainer::new("myapp", "docker.io/library/alpine:latest")
        .kubernetes(handle.namespace(), handle.pod_name())
        .debug(true)
        .build()?;

    print_test(4, "BuildahContainer created with Kubernetes target", true);
    println!("  Container: {}", builder.name());
    println!("  Base Image: {}", builder.image());
    tests_passed += 1;

    // Test 5: Run commands in the container (inside the Kubernetes pod)
    print_section("Test 5: Install Packages");
    let result = builder.run("apk add --no-cache busybox-extras")?;
    let success = result.success;
    print_test(5, "Package installation", success);
    if success {
        tests_passed += 1;
    } else {
        println!("  Failed: {}", result.stderr);
        tests_failed += 1;
    }

    // Test 6: Create app directory and content
    print_section("Test 6: Create Application Files");
    builder.run("mkdir -p /app")?;

    let html_content = r#"<!DOCTYPE html>
<html>
<head><title>Hello from Kubernetes</title></head>
<body>
  <h1>Hello from Kubernetes Registry!</h1>
  <p>This image was built using BuilderConfig with Kubernetes execution.</p>
</body>
</html>"#;

    // Write HTML content to the container
    builder.run(&format!(
        "cat > /app/index.html << 'EOF'\n{}EOF",
        html_content
    ))?;

    print_test(6, "Application files created", true);
    tests_passed += 1;

    // Test 7: Configure the image
    print_section("Test 7: Configure Image Metadata");
    builder.set_cmd(r#"["nc", "-lp", "8080", "-e", "cat", "/app/index.html"]"#)?;
    print_test(7, "Image metadata configured", true);
    tests_passed += 1;

    // Test 8: Commit the container to an image
    print_section("Test 8: Commit Container to Image");
    let registry_image = format!("{}/myapp:v1", deployer.image_prefix());
    let commit_result = builder.commit(&registry_image)?;

    let commit_success = commit_result.success;
    print_test(8, "Image committed", commit_success);
    if commit_success {
        println!("  Image: {}", registry_image);
        tests_passed += 1;
    } else {
        println!("  Failed: {}", commit_result.stderr);
        tests_failed += 1;
    }

    // Test 9: Push image to registry
    // Use the builder's push method which uses the Kubernetes executor
    print_section("Test 9: Push Image to Registry");
    println!("Pushing to registry (this may take a moment)...\n");

    let push_result = builder.push(
        &registry_image,
        &format!("docker://{}", registry_image),
        false, // tls_verify = false for local registry
    );

    match push_result {
        Ok(result) if result.success => {
            print_test(9, "Image pushed to registry", true);
            println!("  Successfully pushed to {}", registry_image);
            tests_passed += 1;
        }
        Ok(result) => {
            print_test(9, "Image pushed to registry", false);
            println!("  Push failed: {}", result.stderr);
            tests_failed += 1;
        }
        Err(e) => {
            print_test(9, "Image pushed to registry", false);
            println!("  Push error: {}", e);
            tests_failed += 1;
        }
    }

    // Test 10: Verify image in registry (uses builder's executor)
    print_section("Test 10: Verify Image");
    let images = builder.list_images()?;
    let image_exists = images
        .iter()
        .any(|img| img.names.iter().any(|name| name.contains("myapp")));

    print_test(10, "Image exists in buildah storage", image_exists);
    println!("  Available images:");
    for img in images.iter().take(5) {
        println!(
            "    {} - {}",
            img.id.chars().take(12).collect::<String>(),
            img.names.join(", ")
        );
    }
    if image_exists {
        tests_passed += 1;
    } else {
        tests_failed += 1;
    }

    // Cleanup the builder container
    builder.remove()?;
    println!("\n✓ Builder container removed");

    // Summary
    print_section("Summary");
    println!(
        "Test Results: {} passed, {} failed\n",
        tests_passed, tests_failed
    );

    if tests_failed > 0 {
        println!("⚠ Some tests failed\n");
        println!("Common Issues:");
        println!("  1. buildah not installed in build pod");
        println!("  2. Registry not ready when pushing");
        println!("  3. Network connectivity issues");
        println!("  4. Insufficient cluster resources");
    } else {
        println!("✓ All tests passed!\n");
    }

    println!("Registry Details:");
    println!("  Endpoint: {}", deployer.connection_string());
    println!("  Image: {}", registry_image);
    println!("  Port: {}", deployer.port());

    println!("\nBuildahContainer API Summary:");
    println!("  // Local execution:");
    println!("  BuildahContainer::new(\"name\", \"image\").build()");
    println!();
    println!("  // Kubernetes execution:");
    println!("  BuildahContainer::new(\"name\", \"image\")");
    println!("      .kubernetes(\"namespace\", \"pod\")");
    println!("      .build()");

    // Cleanup
    print_section("Cleanup");
    println!("Cleaning up resources...");

    handle.destroy().await?;
    println!("✓ Build machine destroyed");

    km.delete_registry("local-registry").await?;
    println!("✓ Registry deleted");

    km.namespace_delete("build-push").await?;
    println!("✓ Namespace deleted");

    // Final status
    print_section("Final Status");
    if tests_failed > 0 {
        println!(
            "✗ Build and push example completed with {} failures\n",
            tests_failed
        );
        println!("Check the output above for error details.");
        std::process::exit(1);
    } else {
        println!("✓ Build and push example finished successfully\n");
        println!("Next Steps:");
        println!("  1. Deploy your app using the built image");
        println!(
            "  2. Pull image from registry: docker pull {}",
            registry_image
        );
        println!(
            "  3. Run locally: docker run -p 8080:8080 {}",
            registry_image
        );
    }

    Ok(())
}
