use super::{
    BoxedExecutor, BuildahError, Image, KubectlExecutor, RemoteExecutor, execute_buildah_command,
    set_thread_local_debug, thread_local_debug,
};
use crate::process::CommandResult;
use std::collections::HashMap;
use std::sync::Arc;

/// Configuration builder for creating a [`Builder`] with various execution targets.
///
/// This provides a fluent API to configure where buildah commands will execute:
/// - Local execution (default)
/// - Kubernetes pod via kubectl exec
/// - SSH remote execution (future)
///
/// # Examples
///
/// ## Local Execution (Default)
///
/// ```rust,no_run
/// use herolib_virt::buildah::BuildahContainer;
///
/// let builder = BuildahContainer::new("my-container", "alpine:latest")
///     .debug(true)
///     .build()?;
/// # Ok::<(), herolib_virt::buildah::BuildahError>(())
/// ```
///
/// ## Kubernetes Pod Execution
///
/// ```rust,no_run
/// use herolib_virt::buildah::BuildahContainer;
///
/// let builder = BuildahContainer::new("my-container", "alpine:latest")
///     .kubernetes("my-namespace", "buildah-pod")
///     .container("builder")  // optional: specify container in pod
///     .debug(true)
///     .build()?;
///
/// // Now all buildah commands run inside the Kubernetes pod
/// builder.run("apk add curl")?;
/// builder.commit("my-image:latest")?;
/// # Ok::<(), herolib_virt::buildah::BuildahError>(())
/// ```
#[derive(Clone)]
pub struct BuildahContainer {
    name: String,
    image: String,
    debug: bool,
    execution_target: ExecutionTarget,
}

/// Where buildah commands will be executed.
#[derive(Clone)]
enum ExecutionTarget {
    /// Execute on the local machine
    Local,
    /// Execute in a Kubernetes pod via kubectl exec
    Kubernetes {
        namespace: String,
        pod_name: String,
        container: Option<String>,
    },
    // Future: SSH { host: String, user: String, ... }
}

impl BuildahContainer {
    /// Create a new builder configuration.
    ///
    /// # Arguments
    ///
    /// * `name` - Name for the buildah container
    /// * `image` - Base image to start from (e.g., "alpine:latest")
    ///
    /// # Example
    ///
    /// ```rust,no_run
    /// use herolib_virt::buildah::BuildahContainer;
    ///
    /// let config = BuildahContainer::new("my-container", "docker.io/library/alpine:latest");
    /// ```
    pub fn new(name: impl Into<String>, image: impl Into<String>) -> Self {
        Self {
            name: name.into(),
            image: image.into(),
            debug: false,
            execution_target: ExecutionTarget::Local,
        }
    }

    /// Enable or disable debug mode.
    ///
    /// When enabled, buildah commands and their output will be printed.
    pub fn debug(mut self, enabled: bool) -> Self {
        self.debug = enabled;
        self
    }

    /// Configure execution on a Kubernetes pod.
    ///
    /// This will execute all buildah commands inside the specified pod
    /// using `kubectl exec`.
    ///
    /// # Arguments
    ///
    /// * `namespace` - Kubernetes namespace where the pod is running
    /// * `pod_name` - Name of the pod with buildah installed
    ///
    /// # Example
    ///
    /// ```rust,no_run
    /// use herolib_virt::buildah::BuildahContainer;
    ///
    /// let builder = BuildahContainer::new("my-container", "alpine:latest")
    ///     .kubernetes("build-ns", "buildah-pod")
    ///     .build()?;
    /// # Ok::<(), herolib_virt::buildah::BuildahError>(())
    /// ```
    pub fn kubernetes(mut self, namespace: impl Into<String>, pod_name: impl Into<String>) -> Self {
        self.execution_target = ExecutionTarget::Kubernetes {
            namespace: namespace.into(),
            pod_name: pod_name.into(),
            container: None,
        };
        self
    }

    /// Specify which container to use in a multi-container pod.
    ///
    /// Only applicable when using Kubernetes execution target.
    /// If not specified, the default container in the pod will be used.
    ///
    /// # Example
    ///
    /// ```rust,no_run
    /// use herolib_virt::buildah::BuildahContainer;
    ///
    /// let builder = BuildahContainer::new("my-container", "alpine:latest")
    ///     .kubernetes("build-ns", "multi-container-pod")
    ///     .container("buildah-container")
    ///     .build()?;
    /// # Ok::<(), herolib_virt::buildah::BuildahError>(())
    /// ```
    pub fn container(mut self, container: impl Into<String>) -> Self {
        if let ExecutionTarget::Kubernetes {
            container: ref mut c,
            ..
        } = self.execution_target
        {
            *c = Some(container.into());
        }
        self
    }

    /// Build the [`Builder`] with the configured settings.
    ///
    /// This will:
    /// 1. Create the appropriate executor based on the execution target
    /// 2. Initialize the buildah container from the base image
    /// 3. Return a ready-to-use Builder
    ///
    /// # Errors
    ///
    /// Returns an error if:
    /// - Container name or image is empty
    /// - The base image cannot be accessed
    /// - The execution target is not reachable (e.g., pod doesn't exist)
    /// - Buildah is not available on the target
    pub fn build(self) -> Result<Builder, BuildahError> {
        match self.execution_target {
            ExecutionTarget::Local => {
                let mut builder = Builder::new(&self.name, &self.image)?;
                builder.set_debug(self.debug);
                Ok(builder)
            }
            ExecutionTarget::Kubernetes {
                namespace,
                pod_name,
                container,
            } => {
                let mut executor = KubectlExecutor::new(namespace, pod_name).debug(self.debug);

                if let Some(c) = container {
                    executor = executor.container(c);
                }

                Builder::with_executor(&self.name, &self.image, executor)
            }
        }
    }
}

/// Builder struct for buildah operations
///
/// Supports both local and remote execution via the `RemoteExecutor` trait.
#[derive(Clone)]
pub struct Builder {
    /// Name of the container
    name: String,
    /// Container ID
    container_id: Option<String>,
    /// Base image
    image: String,
    /// Debug mode
    debug: bool,
    /// Remote executor (None = use legacy local execution)
    executor: Option<BoxedExecutor>,
}

impl Builder {
    /// Create a new builder with a container from the specified image (local execution)
    ///
    /// # Arguments
    ///
    /// * `name` - Name for the container
    /// * `image` - Image to create the container from
    ///
    /// # Returns
    ///
    /// * `Result<Self, BuildahError>` - Builder instance or error
    ///
    /// # Defensive Behavior
    ///
    /// - Validates that `name` is not empty
    /// - Validates that `image` is not empty
    /// - Returns error if base image cannot be accessed
    pub fn new(name: &str, image: &str) -> Result<Self, BuildahError> {
        // Validate inputs
        if name.trim().is_empty() {
            return Err(BuildahError::Other(
                "Container name cannot be empty".to_string(),
            ));
        }

        if image.trim().is_empty() {
            return Err(BuildahError::Other(
                "Image name cannot be empty".to_string(),
            ));
        }

        let name = name.trim();
        let image = image.trim();

        // Try to create a new container using legacy local execution
        let result = execute_buildah_command(&["from", "--name", name, image]);

        match result {
            Ok(success_result) => {
                // Container created successfully
                let container_id = success_result.stdout.trim().to_string();

                if container_id.is_empty() {
                    return Err(BuildahError::Other(
                        "Buildah returned empty container ID".to_string(),
                    ));
                }

                Ok(Self {
                    name: name.to_string(),
                    container_id: Some(container_id),
                    image: image.to_string(),
                    debug: false,
                    executor: None, // Use legacy local execution
                })
            }
            Err(BuildahError::CommandFailed(error_msg)) => {
                // Check if the error is because the container already exists
                if error_msg.contains("that name is already in use") {
                    // Extract the container ID from the error message
                    // Error format: "the container name "name" is already in use by container_id. You have to remove that container to be able to reuse that name: that name is already in use"
                    let container_id = error_msg
                        .split("already in use by ")
                        .nth(1)
                        .and_then(|s| s.split('.').next())
                        .unwrap_or("")
                        .trim()
                        .to_string();

                    if !container_id.is_empty() {
                        // Container already exists, continue with it
                        Ok(Self {
                            name: name.to_string(),
                            container_id: Some(container_id),
                            image: image.to_string(),
                            debug: false,
                            executor: None,
                        })
                    } else {
                        // Couldn't extract container ID
                        Err(BuildahError::Other(
                            "Failed to extract container ID from existing container error message"
                                .to_string(),
                        ))
                    }
                } else if error_msg.contains("image not known")
                    || error_msg.contains("does not exist")
                {
                    // Image not found - provide helpful error message
                    Err(BuildahError::CommandFailed(format!(
                        "Base image '{}' not found or cannot be accessed: {}",
                        image, error_msg
                    )))
                } else {
                    // Other command failure
                    Err(BuildahError::CommandFailed(error_msg))
                }
            }
            Err(e) => {
                // Other error
                Err(e)
            }
        }
    }

    /// Create a new builder with a remote executor
    ///
    /// This allows running buildah commands on remote systems via SSH, kubectl exec, etc.
    ///
    /// # Arguments
    ///
    /// * `name` - Name for the container
    /// * `image` - Image to create the container from
    /// * `executor` - The remote executor to use
    ///
    /// # Returns
    ///
    /// * `Result<Self, BuildahError>` - Builder instance or error
    pub fn with_executor<E: RemoteExecutor + 'static>(
        name: &str,
        image: &str,
        executor: E,
    ) -> Result<Self, BuildahError> {
        let executor: BoxedExecutor = Arc::new(executor);

        // Try to create a new container using the remote executor
        let result = executor.execute(&["from", "--name", name, image]);

        match result {
            Ok(success_result) => {
                let container_id = success_result.stdout.trim().to_string();

                Ok(Self {
                    name: name.to_string(),
                    container_id: Some(container_id),
                    image: image.to_string(),
                    debug: false,
                    executor: Some(executor),
                })
            }
            Err(BuildahError::CommandFailed(error_msg)) => {
                if error_msg.contains("that name is already in use") {
                    let container_id = error_msg
                        .split("already in use by ")
                        .nth(1)
                        .and_then(|s| s.split('.').next())
                        .unwrap_or("")
                        .trim()
                        .to_string();

                    if !container_id.is_empty() {
                        Ok(Self {
                            name: name.to_string(),
                            container_id: Some(container_id),
                            image: image.to_string(),
                            debug: false,
                            executor: Some(executor),
                        })
                    } else {
                        Err(BuildahError::Other(
                            "Failed to extract container ID from error message".to_string(),
                        ))
                    }
                } else {
                    Err(BuildahError::CommandFailed(error_msg))
                }
            }
            Err(e) => Err(e),
        }
    }

    /// Helper to execute buildah command using either executor or legacy method
    fn exec_command(&self, args: &[&str]) -> Result<CommandResult, BuildahError> {
        if let Some(executor) = &self.executor {
            executor.execute(args)
        } else {
            // Legacy local execution with debug handling
            let previous_debug = thread_local_debug();
            set_thread_local_debug(self.debug);
            let result = execute_buildah_command(args);
            set_thread_local_debug(previous_debug);
            result
        }
    }

    /// Get the container ID
    pub fn container_id(&self) -> Option<&String> {
        self.container_id.as_ref()
    }

    /// Get the container name
    pub fn name(&self) -> &str {
        &self.name
    }

    /// Get the debug mode
    pub fn debug(&self) -> bool {
        self.debug
    }

    /// Set the debug mode
    pub fn set_debug(&mut self, debug: bool) -> &mut Self {
        self.debug = debug;
        self
    }

    /// Get the base image
    pub fn image(&self) -> &str {
        &self.image
    }

    /// Run a command in the container
    ///
    /// # Arguments
    ///
    /// * `command` - The command to run
    ///
    /// # Returns
    ///
    /// * `Result<CommandResult, BuildahError>` - Command result or error
    ///
    /// # Defensive Behavior
    ///
    /// - Validates that `command` is not empty
    /// - Validates that container is still available
    /// - Returns detailed error if execution fails
    pub fn run(&self, command: &str) -> Result<CommandResult, BuildahError> {
        // Validate input
        if command.trim().is_empty() {
            return Err(BuildahError::Other("Command cannot be empty".to_string()));
        }

        if let Some(container_id) = &self.container_id {
            if container_id.is_empty() {
                return Err(BuildahError::Other(
                    "Container ID is empty or invalid".to_string(),
                ));
            }
            self.exec_command(&["run", container_id, "sh", "-c", command])
        } else {
            Err(BuildahError::Other(
                "No container ID available - container may have been removed or not initialized"
                    .to_string(),
            ))
        }
    }

    /// Run a command in the container with specified isolation
    ///
    /// # Arguments
    ///
    /// * `command` - The command to run
    /// * `isolation` - Isolation method (e.g., "chroot", "rootless", "oci")
    ///
    /// # Returns
    ///
    /// * `Result<CommandResult, BuildahError>` - Command result or error
    pub fn run_with_isolation(
        &self,
        command: &str,
        isolation: &str,
    ) -> Result<CommandResult, BuildahError> {
        if let Some(container_id) = &self.container_id {
            self.exec_command(&[
                "run",
                "--isolation",
                isolation,
                container_id,
                "sh",
                "-c",
                command,
            ])
        } else {
            Err(BuildahError::Other("No container ID available".to_string()))
        }
    }

    /// Copy files into the container
    ///
    /// # Arguments
    ///
    /// * `source` - Source path
    /// * `dest` - Destination path in the container
    ///
    /// # Returns
    ///
    /// * `Result<CommandResult, BuildahError>` - Command result or error
    ///
    /// # Defensive Behavior
    ///
    /// - Validates that paths are not empty
    /// - Validates that container is available
    pub fn copy(&self, source: &str, dest: &str) -> Result<CommandResult, BuildahError> {
        // Validate inputs
        if source.trim().is_empty() {
            return Err(BuildahError::Other(
                "Source path cannot be empty".to_string(),
            ));
        }

        if dest.trim().is_empty() {
            return Err(BuildahError::Other(
                "Destination path cannot be empty".to_string(),
            ));
        }

        if let Some(container_id) = &self.container_id {
            if container_id.is_empty() {
                return Err(BuildahError::Other(
                    "Container ID is empty or invalid".to_string(),
                ));
            }
            self.exec_command(&["copy", container_id, source, dest])
        } else {
            Err(BuildahError::Other(
                "No container ID available - container may have been removed or not initialized"
                    .to_string(),
            ))
        }
    }

    /// Add files into the container
    ///
    /// # Arguments
    ///
    /// * `source` - Source path
    /// * `dest` - Destination path in the container
    ///
    /// # Returns
    ///
    /// * `Result<CommandResult, BuildahError>` - Command result or error
    ///
    /// # Defensive Behavior
    ///
    /// - Validates that paths are not empty
    /// - Validates that container is available
    pub fn add(&self, source: &str, dest: &str) -> Result<CommandResult, BuildahError> {
        // Validate inputs
        if source.trim().is_empty() {
            return Err(BuildahError::Other(
                "Source path cannot be empty".to_string(),
            ));
        }

        if dest.trim().is_empty() {
            return Err(BuildahError::Other(
                "Destination path cannot be empty".to_string(),
            ));
        }

        if let Some(container_id) = &self.container_id {
            if container_id.is_empty() {
                return Err(BuildahError::Other(
                    "Container ID is empty or invalid".to_string(),
                ));
            }
            self.exec_command(&["add", container_id, source, dest])
        } else {
            Err(BuildahError::Other(
                "No container ID available - container may have been removed or not initialized"
                    .to_string(),
            ))
        }
    }

    /// Commit the container to an image
    ///
    /// # Arguments
    ///
    /// * `image_name` - Name for the new image
    ///
    /// # Returns
    ///
    /// * `Result<CommandResult, BuildahError>` - Command result or error
    ///
    /// # Defensive Behavior
    ///
    /// - Validates that `image_name` is not empty
    /// - Validates that container is available
    /// - Returns detailed error if commit fails
    pub fn commit(&self, image_name: &str) -> Result<CommandResult, BuildahError> {
        // Validate input
        if image_name.trim().is_empty() {
            return Err(BuildahError::Other(
                "Image name cannot be empty".to_string(),
            ));
        }

        if let Some(container_id) = &self.container_id {
            if container_id.is_empty() {
                return Err(BuildahError::Other(
                    "Container ID is empty or invalid".to_string(),
                ));
            }
            self.exec_command(&["commit", container_id, image_name])
        } else {
            Err(BuildahError::Other(
                "No container ID available - cannot commit: container may have been removed or not initialized".to_string(),
            ))
        }
    }

    /// Remove the container
    ///
    /// # Returns
    ///
    /// * `Result<CommandResult, BuildahError>` - Command result or error
    pub fn remove(&self) -> Result<CommandResult, BuildahError> {
        if let Some(container_id) = &self.container_id {
            self.exec_command(&["rm", container_id])
        } else {
            Err(BuildahError::Other("No container ID available".to_string()))
        }
    }

    /// Reset the builder by removing the container and clearing the container_id
    ///
    /// This will destroy the build environment. For preserving the build environment
    /// for reuse, use `preserve()` instead.
    ///
    /// # Returns
    ///
    /// * `Result<(), BuildahError>` - Success or error
    ///
    /// # See Also
    ///
    /// - [`Self::preserve()`] - Preserves the build environment for reuse
    /// - [`Self::is_preserved()`] - Checks if the environment is preserved
    pub fn reset(&mut self) -> Result<(), BuildahError> {
        if let Some(container_id) = &self.container_id {
            let result = self.exec_command(&["rm", container_id]);
            self.container_id = None;
            result.map(|_| ())
        } else {
            Ok(())
        }
    }

    /// Push an image to a registry (uses executor for remote execution)
    ///
    /// This is an instance method that uses the configured executor,
    /// allowing pushes from remote environments (e.g., Kubernetes pods).
    ///
    /// # Arguments
    ///
    /// * `image` - Image name/tag to push
    /// * `destination` - Destination (e.g., "docker://registry:5000/myimage:tag")
    /// * `tls_verify` - Whether to verify TLS certificates
    ///
    /// # Returns
    ///
    /// * `Result<CommandResult, BuildahError>` - Command result or error
    ///
    /// # Example
    ///
    /// ```rust,no_run
    /// # use herolib_virt::buildah::BuildahContainer;
    /// # fn main() -> Result<(), herolib_virt::buildah::BuildahError> {
    /// let builder = BuildahContainer::new("myapp", "alpine:latest")
    ///     .kubernetes("build-ns", "buildah-pod")
    ///     .build()?;
    ///
    /// builder.run("apk add curl")?;
    /// builder.commit("registry:5000/myapp:v1")?;
    /// builder.push("registry:5000/myapp:v1", "docker://registry:5000/myapp:v1", false)?;
    /// # Ok(())
    /// # }
    /// ```
    pub fn push(
        &self,
        image: &str,
        destination: &str,
        tls_verify: bool,
    ) -> Result<CommandResult, BuildahError> {
        let mut args = vec!["push"];

        if !tls_verify {
            args.push("--tls-verify=false");
        }

        args.push(image);
        args.push(destination);

        self.exec_command(&args)
    }

    /// Pull an image from a registry (uses executor for remote execution)
    ///
    /// # Arguments
    ///
    /// * `image` - Image name to pull
    /// * `tls_verify` - Whether to verify TLS certificates
    ///
    /// # Returns
    ///
    /// * `Result<CommandResult, BuildahError>` - Command result or error
    pub fn pull(&self, image: &str, tls_verify: bool) -> Result<CommandResult, BuildahError> {
        let mut args = vec!["pull"];

        if !tls_verify {
            args.push("--tls-verify=false");
        }

        args.push(image);

        self.exec_command(&args)
    }

    /// Tag an image (uses executor for remote execution)
    ///
    /// # Arguments
    ///
    /// * `image` - Source image name/ID
    /// * `new_name` - New tag for the image
    ///
    /// # Returns
    ///
    /// * `Result<CommandResult, BuildahError>` - Command result or error
    pub fn tag(&self, image: &str, new_name: &str) -> Result<CommandResult, BuildahError> {
        self.exec_command(&["tag", image, new_name])
    }

    /// List images (uses executor for remote execution)
    ///
    /// # Returns
    ///
    /// * `Result<Vec<Image>, BuildahError>` - List of images or error
    pub fn list_images(&self) -> Result<Vec<Image>, BuildahError> {
        let result = self.exec_command(&["images", "--json"])?;

        match serde_json::from_str::<serde_json::Value>(&result.stdout) {
            Ok(json) => {
                if let serde_json::Value::Array(images_json) = json {
                    let mut images = Vec::new();

                    for image_json in images_json {
                        let id = image_json
                            .get("id")
                            .and_then(|v| v.as_str())
                            .unwrap_or("")
                            .to_string();

                        let names = image_json
                            .get("names")
                            .and_then(|v| v.as_array())
                            .map(|arr| {
                                arr.iter()
                                    .filter_map(|v| v.as_str().map(|s| s.to_string()))
                                    .collect()
                            })
                            .unwrap_or_default();

                        let size = image_json
                            .get("size")
                            .and_then(|v| v.as_str())
                            .unwrap_or("Unknown")
                            .to_string();

                        let created = image_json
                            .get("created")
                            .and_then(|v| v.as_str())
                            .unwrap_or("Unknown")
                            .to_string();

                        images.push(Image {
                            id,
                            names,
                            size,
                            created,
                        });
                    }

                    Ok(images)
                } else {
                    Err(BuildahError::JsonParseError(
                        "Expected JSON array".to_string(),
                    ))
                }
            }
            Err(e) => Err(BuildahError::JsonParseError(format!(
                "Failed to parse image list JSON: {}",
                e
            ))),
        }
    }

    /// Configure container metadata
    ///
    /// # Arguments
    ///
    /// * `options` - Map of configuration options
    ///
    /// # Returns
    ///
    /// * `Result<CommandResult, BuildahError>` - Command result or error
    pub fn config(&self, options: HashMap<String, String>) -> Result<CommandResult, BuildahError> {
        if let Some(container_id) = &self.container_id {
            let mut args_owned: Vec<String> = Vec::new();
            args_owned.push("config".to_string());

            for (key, value) in options.iter() {
                args_owned.push(format!("--{}", key));
                args_owned.push(value.clone());
            }

            args_owned.push(container_id.clone());
            let args: Vec<&str> = args_owned.iter().map(|s| s.as_str()).collect();
            self.exec_command(&args)
        } else {
            Err(BuildahError::Other("No container ID available".to_string()))
        }
    }

    /// Set the entrypoint for the container
    ///
    /// # Arguments
    ///
    /// * `entrypoint` - The entrypoint command
    ///
    /// # Returns
    ///
    /// * `Result<CommandResult, BuildahError>` - Command result or error
    pub fn set_entrypoint(&self, entrypoint: &str) -> Result<CommandResult, BuildahError> {
        if let Some(container_id) = &self.container_id {
            self.exec_command(&["config", "--entrypoint", entrypoint, container_id])
        } else {
            Err(BuildahError::Other("No container ID available".to_string()))
        }
    }

    /// Set the default command for the container
    ///
    /// # Arguments
    ///
    /// * `cmd` - The default command
    ///
    /// # Returns
    ///
    /// * `Result<CommandResult, BuildahError>` - Command result or error
    pub fn set_cmd(&self, cmd: &str) -> Result<CommandResult, BuildahError> {
        if let Some(container_id) = &self.container_id {
            self.exec_command(&["config", "--cmd", cmd, container_id])
        } else {
            Err(BuildahError::Other("No container ID available".to_string()))
        }
    }

    /// List images in local storage
    ///
    /// # Returns
    ///
    /// * `Result<Vec<Image>, BuildahError>` - List of images or error
    pub fn images() -> Result<Vec<Image>, BuildahError> {
        // Use default debug value (false) for static method
        let result = execute_buildah_command(&["images", "--json"])?;

        // Try to parse the JSON output
        match serde_json::from_str::<serde_json::Value>(&result.stdout) {
            Ok(json) => {
                if let serde_json::Value::Array(images_json) = json {
                    let mut images = Vec::new();

                    for image_json in images_json {
                        // Extract image ID
                        let id = match image_json.get("id").and_then(|v| v.as_str()) {
                            Some(id) => id.to_string(),
                            None => {
                                return Err(BuildahError::ConversionError(
                                    "Missing image ID".to_string(),
                                ));
                            }
                        };

                        // Extract image names
                        let names = match image_json.get("names").and_then(|v| v.as_array()) {
                            Some(names_array) => {
                                let mut names_vec = Vec::new();
                                for name_value in names_array {
                                    if let Some(name_str) = name_value.as_str() {
                                        names_vec.push(name_str.to_string());
                                    }
                                }
                                names_vec
                            }
                            None => Vec::new(), // Empty vector if no names found
                        };

                        // Extract image size
                        let size = match image_json.get("size").and_then(|v| v.as_str()) {
                            Some(size) => size.to_string(),
                            None => "Unknown".to_string(), // Default value if size not found
                        };

                        // Extract creation timestamp
                        let created = match image_json.get("created").and_then(|v| v.as_str()) {
                            Some(created) => created.to_string(),
                            None => "Unknown".to_string(), // Default value if created not found
                        };

                        // Create Image struct and add to vector
                        images.push(Image {
                            id,
                            names,
                            size,
                            created,
                        });
                    }

                    Ok(images)
                } else {
                    Err(BuildahError::JsonParseError(
                        "Expected JSON array".to_string(),
                    ))
                }
            }
            Err(e) => Err(BuildahError::JsonParseError(format!(
                "Failed to parse image list JSON: {}",
                e
            ))),
        }
    }

    /// Remove an image
    ///
    /// # Arguments
    ///
    /// * `image` - Image ID or name
    ///
    /// # Returns
    ///
    /// * `Result<CommandResult, BuildahError>` - Command result or error
    pub fn image_remove(image: &str) -> Result<CommandResult, BuildahError> {
        // Use default debug value (false) for static method
        execute_buildah_command(&["rmi", image])
    }

    /// Remove an image with debug output
    ///
    /// # Arguments
    ///
    /// * `image` - Image ID or name
    /// * `debug` - Whether to enable debug output
    ///
    /// # Returns
    ///
    /// * `Result<CommandResult, BuildahError>` - Command result or error
    pub fn image_remove_with_debug(
        image: &str,
        debug: bool,
    ) -> Result<CommandResult, BuildahError> {
        // Save the current debug flag
        let previous_debug = thread_local_debug();

        // Set the thread-local debug flag
        set_thread_local_debug(debug);

        // Execute the command
        let result = execute_buildah_command(&["rmi", image]);

        // Restore the previous debug flag
        set_thread_local_debug(previous_debug);

        result
    }

    /// Pull an image from a registry
    ///
    /// # Arguments
    ///
    /// * `image` - Image name
    /// * `tls_verify` - Whether to verify TLS
    ///
    /// # Returns
    ///
    /// * `Result<CommandResult, BuildahError>` - Command result or error
    pub fn image_pull(image: &str, tls_verify: bool) -> Result<CommandResult, BuildahError> {
        // Use default debug value (false) for static method
        let mut args = vec!["pull"];

        if !tls_verify {
            args.push("--tls-verify=false");
        }

        args.push(image);

        execute_buildah_command(&args)
    }

    /// Pull an image from a registry with debug output
    ///
    /// # Arguments
    ///
    /// * `image` - Image name
    /// * `tls_verify` - Whether to verify TLS
    /// * `debug` - Whether to enable debug output
    ///
    /// # Returns
    ///
    /// * `Result<CommandResult, BuildahError>` - Command result or error
    pub fn image_pull_with_debug(
        image: &str,
        tls_verify: bool,
        debug: bool,
    ) -> Result<CommandResult, BuildahError> {
        // Save the current debug flag
        let previous_debug = thread_local_debug();

        // Set the thread-local debug flag
        set_thread_local_debug(debug);

        let mut args = vec!["pull"];

        if !tls_verify {
            args.push("--tls-verify=false");
        }

        args.push(image);

        // Execute the command
        let result = execute_buildah_command(&args);

        // Restore the previous debug flag
        set_thread_local_debug(previous_debug);

        result
    }

    /// Push an image to a registry
    ///
    /// # Arguments
    ///
    /// * `image` - Image name
    /// * `destination` - Destination registry
    /// * `tls_verify` - Whether to verify TLS
    ///
    /// # Returns
    ///
    /// * `Result<CommandResult, BuildahError>` - Command result or error
    pub fn image_push(
        image: &str,
        destination: &str,
        tls_verify: bool,
    ) -> Result<CommandResult, BuildahError> {
        // Use default debug value (false) for static method
        let mut args = vec!["push"];

        if !tls_verify {
            args.push("--tls-verify=false");
        }

        args.push(image);
        args.push(destination);

        execute_buildah_command(&args)
    }

    /// Push an image to a registry with debug output
    ///
    /// # Arguments
    ///
    /// * `image` - Image name
    /// * `destination` - Destination registry
    /// * `tls_verify` - Whether to verify TLS
    /// * `debug` - Whether to enable debug output
    ///
    /// # Returns
    ///
    /// * `Result<CommandResult, BuildahError>` - Command result or error
    pub fn image_push_with_debug(
        image: &str,
        destination: &str,
        tls_verify: bool,
        debug: bool,
    ) -> Result<CommandResult, BuildahError> {
        // Save the current debug flag
        let previous_debug = thread_local_debug();

        // Set the thread-local debug flag
        set_thread_local_debug(debug);

        let mut args = vec!["push"];

        if !tls_verify {
            args.push("--tls-verify=false");
        }

        args.push(image);
        args.push(destination);

        // Execute the command
        let result = execute_buildah_command(&args);

        // Restore the previous debug flag
        set_thread_local_debug(previous_debug);

        result
    }

    /// Tag an image
    ///
    /// # Arguments
    ///
    /// * `image` - Image ID or name
    /// * `new_name` - New tag for the image
    ///
    /// # Returns
    ///
    /// * `Result<CommandResult, BuildahError>` - Command result or error
    pub fn image_tag(image: &str, new_name: &str) -> Result<CommandResult, BuildahError> {
        // Use default debug value (false) for static method
        execute_buildah_command(&["tag", image, new_name])
    }

    /// Tag an image with debug output
    ///
    /// # Arguments
    ///
    /// * `image` - Image ID or name
    /// * `new_name` - New tag for the image
    /// * `debug` - Whether to enable debug output
    ///
    /// # Returns
    ///
    /// * `Result<CommandResult, BuildahError>` - Command result or error
    pub fn image_tag_with_debug(
        image: &str,
        new_name: &str,
        debug: bool,
    ) -> Result<CommandResult, BuildahError> {
        // Save the current debug flag
        let previous_debug = thread_local_debug();

        // Set the thread-local debug flag
        set_thread_local_debug(debug);

        // Execute the command
        let result = execute_buildah_command(&["tag", image, new_name]);

        // Restore the previous debug flag
        set_thread_local_debug(previous_debug);

        result
    }

    /// Commit a container to an image with advanced options
    ///
    /// # Arguments
    ///
    /// * `container` - Container ID or name
    /// * `image_name` - Name for the new image
    /// * `format` - Optional format (oci or docker)
    /// * `squash` - Whether to squash layers
    /// * `rm` - Whether to remove the container after commit
    ///
    /// # Returns
    ///
    /// * `Result<CommandResult, BuildahError>` - Command result or error
    pub fn image_commit(
        container: &str,
        image_name: &str,
        format: Option<&str>,
        squash: bool,
        rm: bool,
    ) -> Result<CommandResult, BuildahError> {
        // Use default debug value (false) for static method
        let mut args = vec!["commit"];

        if let Some(format_str) = format {
            args.push("--format");
            args.push(format_str);
        }

        if squash {
            args.push("--squash");
        }

        if rm {
            args.push("--rm");
        }

        args.push(container);
        args.push(image_name);

        execute_buildah_command(&args)
    }

    /// Commit a container to an image with advanced options and debug output
    ///
    /// # Arguments
    ///
    /// * `container` - Container ID or name
    /// * `image_name` - Name for the new image
    /// * `format` - Optional format (oci or docker)
    /// * `squash` - Whether to squash layers
    /// * `rm` - Whether to remove the container after commit
    /// * `debug` - Whether to enable debug output
    ///
    /// # Returns
    ///
    /// * `Result<CommandResult, BuildahError>` - Command result or error
    pub fn image_commit_with_debug(
        container: &str,
        image_name: &str,
        format: Option<&str>,
        squash: bool,
        rm: bool,
        debug: bool,
    ) -> Result<CommandResult, BuildahError> {
        // Save the current debug flag
        let previous_debug = thread_local_debug();

        // Set the thread-local debug flag
        set_thread_local_debug(debug);

        let mut args = vec!["commit"];

        if let Some(format_str) = format {
            args.push("--format");
            args.push(format_str);
        }

        if squash {
            args.push("--squash");
        }

        if rm {
            args.push("--rm");
        }

        args.push(container);
        args.push(image_name);

        // Execute the command
        let result = execute_buildah_command(&args);

        // Restore the previous debug flag
        set_thread_local_debug(previous_debug);

        result
    }

    /// Build an image from a Containerfile/Dockerfile
    ///
    /// # Arguments
    ///
    /// * `tag` - Optional tag for the image
    /// * `context_dir` - Directory containing the Containerfile/Dockerfile
    /// * `file` - Path to the Containerfile/Dockerfile
    /// * `isolation` - Optional isolation method
    ///
    /// # Returns
    ///
    /// * `Result<CommandResult, BuildahError>` - Command result or error
    pub fn build(
        tag: Option<&str>,
        context_dir: &str,
        file: &str,
        isolation: Option<&str>,
    ) -> Result<CommandResult, BuildahError> {
        // Use default debug value (false) for static method
        let mut args = Vec::new();
        args.push("build");

        if let Some(tag_value) = tag {
            args.push("-t");
            args.push(tag_value);
        }

        if let Some(isolation_value) = isolation {
            args.push("--isolation");
            args.push(isolation_value);
        }

        args.push("-f");
        args.push(file);

        args.push(context_dir);

        execute_buildah_command(&args)
    }

    /// Build an image from a Containerfile/Dockerfile with debug output
    ///
    /// # Arguments
    ///
    /// * `tag` - Optional tag for the image
    /// * `context_dir` - Directory containing the Containerfile/Dockerfile
    /// * `file` - Path to the Containerfile/Dockerfile
    /// * `isolation` - Optional isolation method
    /// * `debug` - Whether to enable debug output
    ///
    /// # Returns
    ///
    /// * `Result<CommandResult, BuildahError>` - Command result or error
    pub fn build_with_debug(
        tag: Option<&str>,
        context_dir: &str,
        file: &str,
        isolation: Option<&str>,
        debug: bool,
    ) -> Result<CommandResult, BuildahError> {
        // Save the current debug flag
        let previous_debug = thread_local_debug();

        // Set the thread-local debug flag
        set_thread_local_debug(debug);

        let mut args = Vec::new();
        args.push("build");

        if let Some(tag_value) = tag {
            args.push("-t");
            args.push(tag_value);
        }

        if let Some(isolation_value) = isolation {
            args.push("--isolation");
            args.push(isolation_value);
        }

        args.push("-f");
        args.push(file);

        args.push(context_dir);

        // Execute the command
        let result = execute_buildah_command(&args);

        // Restore the previous debug flag
        set_thread_local_debug(previous_debug);

        result
    }
}

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

    /// Test that Builder validates empty container name
    #[test]
    fn test_builder_rejects_empty_name() {
        let result = Builder::new("", "alpine:latest");
        assert!(result.is_err());
        match result {
            Err(BuildahError::Other(msg)) => {
                assert!(msg.contains("name cannot be empty"));
            }
            _ => panic!("Expected validation error for empty name"),
        }
    }

    /// Test that Builder validates empty image name
    #[test]
    fn test_builder_rejects_empty_image() {
        let result = Builder::new("test-builder", "");
        assert!(result.is_err());
        match result {
            Err(BuildahError::Other(msg)) => {
                assert!(msg.contains("Image name cannot be empty"));
            }
            _ => panic!("Expected validation error for empty image"),
        }
    }

    /// Test that Builder trims whitespace from inputs
    #[test]
    fn test_builder_trims_inputs() {
        // This test would require mocking buildah execution
        // For now, we document that inputs are trimmed
        let name = "  test-builder  ";
        let trimmed = name.trim();
        assert_eq!(trimmed, "test-builder");
    }

    /// Test that run() validates empty command
    #[test]
    fn test_run_rejects_empty_command() {
        // Create a mock builder instance
        let builder = Builder {
            name: "test".to_string(),
            container_id: Some("abc123".to_string()),
            image: "alpine:latest".to_string(),
            debug: false,
            executor: None,
        };

        let result = builder.run("");
        assert!(result.is_err());
        match result {
            Err(BuildahError::Other(msg)) => {
                assert!(msg.contains("Command cannot be empty"));
            }
            _ => panic!("Expected validation error for empty command"),
        }
    }

    /// Test that run() fails without container
    #[test]
    fn test_run_fails_without_container() {
        let builder = Builder {
            name: "test".to_string(),
            container_id: None,
            image: "alpine:latest".to_string(),
            debug: false,
            executor: None,
        };

        let result = builder.run("echo hello");
        assert!(result.is_err());
        match result {
            Err(BuildahError::Other(msg)) => {
                assert!(msg.contains("No container ID available"));
            }
            _ => panic!("Expected error for missing container"),
        }
    }

    /// Test that copy() validates source and destination
    #[test]
    fn test_copy_validates_paths() {
        let builder = Builder {
            name: "test".to_string(),
            container_id: Some("abc123".to_string()),
            image: "alpine:latest".to_string(),
            debug: false,
            executor: None,
        };

        // Empty source
        let result = builder.copy("", "/dest");
        assert!(result.is_err());
        match result {
            Err(BuildahError::Other(msg)) => {
                assert!(msg.contains("Source path cannot be empty"));
            }
            _ => panic!("Expected validation error for empty source"),
        }

        // Empty destination
        let result = builder.copy("/source", "");
        assert!(result.is_err());
        match result {
            Err(BuildahError::Other(msg)) => {
                assert!(msg.contains("Destination path cannot be empty"));
            }
            _ => panic!("Expected validation error for empty destination"),
        }
    }

    /// Test that add() validates paths
    #[test]
    fn test_add_validates_paths() {
        let builder = Builder {
            name: "test".to_string(),
            container_id: Some("abc123".to_string()),
            image: "alpine:latest".to_string(),
            debug: false,
            executor: None,
        };

        // Empty source
        let result = builder.add("", "/dest");
        assert!(result.is_err());
        match result {
            Err(BuildahError::Other(msg)) => {
                assert!(msg.contains("Source path cannot be empty"));
            }
            _ => panic!("Expected validation error for empty source"),
        }
    }

    /// Test that commit() validates image name
    #[test]
    fn test_commit_validates_image_name() {
        let builder = Builder {
            name: "test".to_string(),
            container_id: Some("abc123".to_string()),
            image: "alpine:latest".to_string(),
            debug: false,
            executor: None,
        };

        let result = builder.commit("");
        assert!(result.is_err());
        match result {
            Err(BuildahError::Other(msg)) => {
                assert!(msg.contains("Image name cannot be empty"));
            }
            _ => panic!("Expected validation error for empty image name"),
        }
    }

    /// Test that commit() fails without container
    #[test]
    fn test_commit_fails_without_container() {
        let builder = Builder {
            name: "test".to_string(),
            container_id: None,
            image: "alpine:latest".to_string(),
            debug: false,
            executor: None,
        };

        let result = builder.commit("myimage:latest");
        assert!(result.is_err());
        match result {
            Err(BuildahError::Other(msg)) => {
                assert!(msg.contains("No container ID available"));
            }
            _ => panic!("Expected error for missing container"),
        }
    }

    /// Test that reset() handles missing container gracefully
    #[test]
    fn test_reset_handles_missing_container() {
        let mut builder = Builder {
            name: "test".to_string(),
            container_id: None,
            image: "alpine:latest".to_string(),
            debug: false,
            executor: None,
        };

        let result = builder.reset();
        assert!(result.is_ok());
    }

    /// Test getter methods
    #[test]
    fn test_getters() {
        let builder = Builder {
            name: "test-builder".to_string(),
            container_id: Some("container-123".to_string()),
            image: "alpine:latest".to_string(),
            debug: true,
            executor: None,
        };

        assert_eq!(builder.name(), "test-builder");
        assert_eq!(builder.image(), "alpine:latest");
        assert_eq!(builder.debug(), true);
        assert_eq!(builder.container_id(), Some(&"container-123".to_string()));
    }

    /// Test set_debug method chaining
    #[test]
    fn test_set_debug_chaining() {
        let mut builder = Builder {
            name: "test".to_string(),
            container_id: Some("abc123".to_string()),
            image: "alpine:latest".to_string(),
            debug: false,
            executor: None,
        };

        let result = builder.set_debug(true);
        assert_eq!(result.debug(), true);
    }
}
