//! Kubernetes client wrapper.
//!
//! This module provides the main entry point for interacting with Kubernetes clusters.

use crate::config::ClientConfig;
use crate::configmap::ConfigMapManager;
use crate::cronjob::CronJobManager;
use crate::deployment::DeploymentManager;
use crate::error::Result;
use crate::gateway::GatewayManager;
use crate::hpa::HpaManager;
use crate::ingress::IngressManager;
use crate::job::JobManager;
use crate::namespace::NamespaceManager;
use crate::networkpolicy::NetworkPolicyManager;
use crate::pvc::PvcManager;
use crate::secret::SecretManager;
use crate::service::ServiceManager;
use kube::Client as KubeClient;

/// The main Kubernetes client for managing cluster resources.
///
/// This is the primary interface for all Kubernetes operations in this library.
/// It provides access to managers for different resource types.
///
/// # Examples
///
/// ```no_run
/// use lmrc_kubernetes::{Client, ClientConfig};
///
/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
/// // Create client with default configuration
/// let config = ClientConfig::infer().await?;
/// let client = Client::new(config, "default").await?;
///
/// // Access deployment manager
/// let deployments = client.deployments();
///
/// // Access service manager
/// let services = client.services();
/// # Ok(())
/// # }
/// ```
#[derive(Clone)]
pub struct Client {
    kube_client: KubeClient,
    namespace: String,
    field_manager: String,
}

impl Client {
    /// Create a new Kubernetes client.
    ///
    /// # Arguments
    ///
    /// * `config` - Client configuration
    /// * `namespace` - Default namespace for operations
    ///
    /// # Errors
    ///
    /// Returns an error if the client cannot be created.
    pub async fn new<S: Into<String>>(config: ClientConfig, namespace: S) -> Result<Self> {
        let kube_client = config.build_client()?;
        let field_manager = config.field_manager().to_string();

        Ok(Self {
            kube_client,
            namespace: namespace.into(),
            field_manager,
        })
    }

    /// Get the deployment manager for this client.
    ///
    /// The deployment manager handles deployment operations like creating,
    /// updating, rolling back, and scaling deployments.
    pub fn deployments(&self) -> DeploymentManager {
        DeploymentManager::new(
            self.kube_client.clone(),
            self.namespace.clone(),
            self.field_manager.clone(),
        )
    }

    /// Get the service manager for this client.
    ///
    /// The service manager handles Kubernetes Service resources.
    pub fn services(&self) -> ServiceManager {
        ServiceManager::new(
            self.kube_client.clone(),
            self.namespace.clone(),
            self.field_manager.clone(),
        )
    }

    /// Get the secret manager for this client.
    ///
    /// The secret manager handles Kubernetes Secret resources including
    /// Docker registry secrets.
    pub fn secrets(&self) -> SecretManager {
        SecretManager::new(
            self.kube_client.clone(),
            self.namespace.clone(),
            self.field_manager.clone(),
        )
    }

    /// Get the namespace manager for this client.
    ///
    /// The namespace manager handles namespace operations.
    pub fn namespaces(&self) -> NamespaceManager {
        NamespaceManager::new(self.kube_client.clone(), self.field_manager.clone())
    }

    /// Get the ConfigMap manager for this client.
    ///
    /// The ConfigMap manager handles ConfigMap resources for configuration data.
    pub fn configmaps(&self) -> ConfigMapManager {
        ConfigMapManager::new(self.kube_client.clone(), self.namespace.clone())
    }

    /// Get the Ingress manager for this client.
    ///
    /// The Ingress manager handles Ingress resources for HTTP/HTTPS routing.
    pub fn ingresses(&self) -> IngressManager {
        IngressManager::new(self.kube_client.clone(), self.namespace.clone())
    }

    /// Get the Gateway API manager for this client.
    ///
    /// The Gateway manager handles Gateway API resources (Gateway and HTTPRoute).
    /// Note: Requires Gateway API CRDs to be installed in the cluster.
    pub fn gateways(&self) -> GatewayManager {
        GatewayManager::new(self.kube_client.clone(), self.namespace.clone())
    }

    /// Get the NetworkPolicy manager for this client.
    ///
    /// The NetworkPolicy manager handles NetworkPolicy resources for network security.
    pub fn network_policies(&self) -> NetworkPolicyManager {
        NetworkPolicyManager::new(self.kube_client.clone(), self.namespace.clone())
    }

    /// Get the Job manager for this client.
    ///
    /// The Job manager handles Job resources for batch processing.
    pub fn jobs(&self) -> JobManager {
        JobManager::new(self.kube_client.clone(), self.namespace.clone())
    }

    /// Get the CronJob manager for this client.
    ///
    /// The CronJob manager handles CronJob resources for scheduled tasks.
    pub fn cronjobs(&self) -> CronJobManager {
        CronJobManager::new(self.kube_client.clone(), self.namespace.clone())
    }

    /// Get the PersistentVolumeClaim manager for this client.
    ///
    /// The PVC manager handles PersistentVolumeClaim resources for persistent storage.
    pub fn pvcs(&self) -> PvcManager {
        PvcManager::new(
            self.kube_client.clone(),
            self.namespace.clone(),
            self.field_manager.clone(),
        )
    }

    /// Get the HorizontalPodAutoscaler manager for this client.
    ///
    /// The HPA manager handles HorizontalPodAutoscaler resources for auto-scaling.
    pub fn hpas(&self) -> HpaManager {
        HpaManager::new(
            self.kube_client.clone(),
            self.namespace.clone(),
            self.field_manager.clone(),
        )
    }

    /// Get the current namespace for this client.
    pub fn namespace(&self) -> &str {
        &self.namespace
    }

    /// Create a new client with a different namespace.
    ///
    /// This is useful when you need to operate in multiple namespaces
    /// with the same connection configuration.
    pub fn with_namespace<S: Into<String>>(&self, namespace: S) -> Self {
        Self {
            kube_client: self.kube_client.clone(),
            namespace: namespace.into(),
            field_manager: self.field_manager.clone(),
        }
    }

    /// Get the underlying kube client (for advanced usage).
    #[allow(dead_code)]
    pub(crate) fn kube_client(&self) -> &KubeClient {
        &self.kube_client
    }

    /// Get the field manager name.
    #[allow(dead_code)]
    pub(crate) fn field_manager(&self) -> &str {
        &self.field_manager
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_client_namespace_switching() {
        // We can't create a real client without a cluster, but we can test the logic
        let namespace1 = "default";
        let namespace2 = "production";

        assert_ne!(namespace1, namespace2);
    }
}
