//! Namespace management for Kubernetes.

use crate::error::{Error, Result};
use k8s_openapi::api::core::v1::Namespace;
use k8s_openapi::apimachinery::pkg::apis::meta::v1::ObjectMeta;
use kube::Client;
use kube::api::{Api, DeleteParams, ListParams, PostParams};
use tracing::info;

/// Manager for Kubernetes Namespace operations.
#[derive(Clone)]
pub struct NamespaceManager {
    client: Client,
    #[allow(dead_code)]
    field_manager: String,
}

impl NamespaceManager {
    pub(crate) fn new(client: Client, field_manager: String) -> Self {
        Self {
            client,
            field_manager,
        }
    }

    /// Create a new namespace.
    ///
    /// # Arguments
    ///
    /// * `name` - Name of the namespace to create
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # use lmrc_kubernetes::{Client, ClientConfig};
    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
    /// # let config = ClientConfig::infer().await?;
    /// # let client = Client::new(config, "default").await?;
    /// let namespaces = client.namespaces();
    /// namespaces.create("my-namespace").await?;
    /// # Ok(())
    /// # }
    /// ```
    pub async fn create(&self, name: &str) -> Result<()> {
        let api: Api<Namespace> = Api::all(self.client.clone());

        info!("Creating namespace: {}", name);

        let namespace = Namespace {
            metadata: ObjectMeta {
                name: Some(name.to_string()),
                ..Default::default()
            },
            ..Default::default()
        };

        api.create(&PostParams::default(), &namespace)
            .await
            .map_err(|e| Error::namespace(format!("Failed to create namespace: {}", e)))?;

        info!("Namespace {} created successfully", name);
        Ok(())
    }

    /// Ensure a namespace exists, creating it if it doesn't.
    ///
    /// This is idempotent - it won't fail if the namespace already exists.
    ///
    /// # Arguments
    ///
    /// * `name` - Name of the namespace to ensure
    pub async fn ensure(&self, name: &str) -> Result<()> {
        let api: Api<Namespace> = Api::all(self.client.clone());

        match api.get(name).await {
            Ok(_) => {
                info!("Namespace '{}' already exists", name);
                Ok(())
            }
            Err(_) => {
                info!("Creating namespace: {}", name);
                let namespace = Namespace {
                    metadata: ObjectMeta {
                        name: Some(name.to_string()),
                        ..Default::default()
                    },
                    ..Default::default()
                };

                api.create(&PostParams::default(), &namespace)
                    .await
                    .map_err(|e| Error::namespace(format!("Failed to create namespace: {}", e)))?;

                info!("Namespace '{}' created successfully", name);
                Ok(())
            }
        }
    }

    /// Delete a namespace.
    ///
    /// Warning: This will delete all resources in the namespace!
    ///
    /// # Arguments
    ///
    /// * `name` - Name of the namespace to delete
    pub async fn delete(&self, name: &str) -> Result<()> {
        let api: Api<Namespace> = Api::all(self.client.clone());

        info!("Deleting namespace: {}", name);

        api.delete(name, &DeleteParams::default())
            .await
            .map_err(|e| Error::namespace(format!("Failed to delete namespace: {}", e)))?;

        info!("Namespace {} deleted", name);
        Ok(())
    }

    /// List all namespaces in the cluster.
    pub async fn list(&self) -> Result<Vec<String>> {
        let api: Api<Namespace> = Api::all(self.client.clone());

        let list = api
            .list(&ListParams::default())
            .await
            .map_err(|e| Error::namespace(format!("Failed to list namespaces: {}", e)))?;

        Ok(list
            .items
            .iter()
            .filter_map(|ns| ns.metadata.name.clone())
            .collect())
    }

    /// Check if a namespace exists.
    pub async fn exists(&self, name: &str) -> Result<bool> {
        let api: Api<Namespace> = Api::all(self.client.clone());
        Ok(api.get(name).await.is_ok())
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_namespace_manager_creation() {
        // Basic smoke test - can't test actual operations without a cluster
        let namespace = "test-namespace";
        assert!(!namespace.is_empty());
    }
}
