//! Rhai wrappers for Kubernetes namespace and resource builders

use crate::kubernetes::{
    NamespaceBuilder,
    RegistryDeployerBuilder, BuildMachine,
};
use rhai::{EvalAltResult, Array, Dynamic};
use super::runtime::{get_runtime, to_rhai_err};
use super::resources::{ConfigMapRhai, SecretRhai, PodRhai, ServiceRhai, DeploymentRhai};
use super::registry::RegistryDeployerBuilderRhai;
use super::build_machine::BuildMachineRhai;
use super::development_machine::DevelopmentMachineRhai;
use crate::kubernetes::DevelopmentMachine;

/// Rhai wrapper for NamespaceBuilder
#[derive(Clone)]
pub struct NamespaceRhai {
    ns: NamespaceBuilder,
}

impl NamespaceRhai {
    /// Create a new NamespaceRhai wrapper
    pub fn new(ns: NamespaceBuilder) -> Self {
        Self { ns }
    }

    /// Reset the namespace
    pub fn reset(&self) -> Result<(), Box<EvalAltResult>> {
        let ns = self.ns.clone();
        let rt = get_runtime();
        rt.block_on(async { ns.reset().await.map_err(|e| format!("Reset error: {}", e)) })
            .map_err(|e| to_rhai_err(e))
    }

    /// Get markdown representation
    pub fn md(&self) -> Result<String, Box<EvalAltResult>> {
        let ns = self.ns.clone();
        let rt = get_runtime();
        rt.block_on(async { ns.md().await.map_err(|e| format!("MD error: {}", e)) })
            .map_err(|e| to_rhai_err(e))
    }

    /// List pods in namespace
    pub fn pods_list(&self) -> Result<Array, Box<EvalAltResult>> {
        let ns = self.ns.clone();
        let rt = get_runtime();
        let list = rt.block_on(async { ns.pods_list().await.map_err(|e| format!("List error: {}", e)) })
            .map_err(|e| to_rhai_err(e))?;
        Ok(list.into_iter().map(Dynamic::from).collect())
    }

    /// List deployments in namespace
    pub fn deployments_list(&self) -> Result<Array, Box<EvalAltResult>> {
        let ns = self.ns.clone();
        let rt = get_runtime();
        let list = rt.block_on(async {
            ns.deployments_list()
                .await
                .map_err(|e| format!("List error: {}", e))
        })
        .map_err(|e| to_rhai_err(e))?;
        Ok(list.into_iter().map(Dynamic::from).collect())
    }

    /// List services in namespace
    pub fn services_list(&self) -> Result<Array, Box<EvalAltResult>> {
        let ns = self.ns.clone();
        let rt = get_runtime();
        let list = rt.block_on(async { ns.services_list().await.map_err(|e| format!("List error: {}", e)) })
            .map_err(|e| to_rhai_err(e))?;
        Ok(list.into_iter().map(Dynamic::from).collect())
    }

    /// List secrets in namespace
    pub fn secrets_list(&self) -> Result<Array, Box<EvalAltResult>> {
        let ns = self.ns.clone();
        let rt = get_runtime();
        let list = rt.block_on(async { ns.secrets_list().await.map_err(|e| format!("List error: {}", e)) })
            .map_err(|e| to_rhai_err(e))?;
        Ok(list.into_iter().map(Dynamic::from).collect())
    }

    /// List configmaps in namespace
    pub fn configmaps_list(&self) -> Result<Array, Box<EvalAltResult>> {
        let ns = self.ns.clone();
        let rt = get_runtime();
        let list = rt.block_on(async {
            ns.configmaps_list()
                .await
                .map_err(|e| format!("List error: {}", e))
        })
        .map_err(|e| to_rhai_err(e))?;
        Ok(list.into_iter().map(Dynamic::from).collect())
    }

    /// Create or get a ConfigMap
    pub fn configmap(&self, name: &str) -> ConfigMapRhai {
        ConfigMapRhai::new(self.ns.configmap(name))
    }

    /// Create or get a Secret
    pub fn secret(&self, name: &str) -> SecretRhai {
        SecretRhai::new(self.ns.secret(name))
    }

    /// Create or get a Pod
    pub fn pod(&self, name: &str) -> PodRhai {
        PodRhai::new(self.ns.pod(name))
    }

    /// Create or get a Service
    pub fn service(&self, name: &str) -> ServiceRhai {
        ServiceRhai::new(self.ns.service(name))
    }

    /// Create or get a Deployment
    pub fn deployment(&self, name: &str) -> DeploymentRhai {
        DeploymentRhai::new(self.ns.deployment(name))
    }

    /// Deploy a Docker Registry
    pub fn registry(&self, name: &str) -> Result<RegistryDeployerBuilderRhai, Box<EvalAltResult>> {
        Ok(RegistryDeployerBuilderRhai::new(
            RegistryDeployerBuilder::new(self.ns.km.clone(), name),
        ))
    }

    /// Provision a Build Machine (pod with buildah)
    pub fn build_machine(&self, name: &str) -> BuildMachineRhai {
        BuildMachineRhai::new(BuildMachine::new(
            self.ns.km.namespace().to_string(),
            name,
        ))
    }

    /// Create or get a Development Machine (pod with SSH access)
    pub fn development_machine(&self, name: &str) -> DevelopmentMachineRhai {
        DevelopmentMachineRhai::new(DevelopmentMachine::new(name))
    }

    /// Delete a registry
    pub fn registry_delete(&self, name: &str) -> Result<(), Box<EvalAltResult>> {
        let ns = self.ns.clone();
        let name = name.to_string();
        let rt = get_runtime();
        rt.block_on(async {
            ns.km
                .delete_registry(&name)
                .await
                .map_err(|e| format!("Delete error: {}", e))
        })
        .map_err(|e| to_rhai_err(e))
    }

    /// Delete the namespace
    pub fn delete(&self) -> Result<(), Box<EvalAltResult>> {
        let ns = self.ns.clone();
        let rt = get_runtime();
        rt.block_on(async {
            ns.km
                .namespace_delete(ns.km.namespace())
                .await
                .map_err(|e| format!("Delete error: {}", e))
        })
        .map_err(|e| to_rhai_err(e))
    }
}
