//! Rhai wrappers for Kubernetes resource builders (ConfigMap, Secret, Pod, Service)

use super::runtime::{get_runtime, to_rhai_err};
use crate::kubernetes::{ConfigMapBuilder, DeploymentBuilder, PodBuilder, SecretBuilder, ServiceBuilder};
use rhai::EvalAltResult;

// ============================================================================
// ConfigMap Wrapper
// ============================================================================

/// Rhai wrapper for ConfigMapBuilder
#[derive(Clone)]
pub struct ConfigMapRhai {
    cm: ConfigMapBuilder,
}

impl ConfigMapRhai {
    /// Create a new ConfigMapRhai wrapper
    pub fn new(cm: ConfigMapBuilder) -> Self {
        Self { cm }
    }

    /// Set a key-value pair
    pub fn set(mut self, key: &str, value: &str) -> Self {
        self.cm = self.cm.set(key, value);
        self
    }

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

    /// Alias for apply (since `do` is reserved in Rhai)
    pub fn do_(&self) -> Result<(), Box<EvalAltResult>> {
        self.apply()
    }
}

// ============================================================================
// Secret Wrapper
// ============================================================================

/// Rhai wrapper for SecretBuilder
#[derive(Clone)]
pub struct SecretRhai {
    secret: SecretBuilder,
}

impl SecretRhai {
    /// Create a new SecretRhai wrapper
    pub fn new(secret: SecretBuilder) -> Self {
        Self { secret }
    }

    /// Set a key-value pair
    pub fn set(mut self, key: &str, value: &str) -> Self {
        self.secret = self.secret.set(key, value);
        self
    }

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

    /// Alias for apply (since `do` is reserved in Rhai)
    pub fn do_(&self) -> Result<(), Box<EvalAltResult>> {
        self.apply()
    }
}

// ============================================================================
// Pod Wrapper
// ============================================================================

/// Rhai wrapper for PodBuilder
#[derive(Clone)]
pub struct PodRhai {
    pod: PodBuilder,
}

impl PodRhai {
    /// Create a new PodRhai wrapper
    pub fn new(pod: PodBuilder) -> Self {
        Self { pod }
    }

    /// Set the image
    pub fn image(mut self, image: &str) -> Self {
        self.pod = self.pod.image(image);
        self
    }

    /// Set environment variable
    pub fn env(mut self, key: &str, value: &str) -> Self {
        self.pod = self.pod.env(key, value);
        self
    }

    /// Add a label
    pub fn label(mut self, key: &str, value: &str) -> Self {
        self.pod = self.pod.label(key, value);
        self
    }

    /// Add a port
    pub fn port(mut self, port: i64) -> Self {
        self.pod = self.pod.port(port as u16);
        self
    }

    /// Set memory request and limit (in MB)
    /// Note: Not yet implemented in the underlying fluent API
    #[allow(deprecated)]
    pub fn memory(mut self, requested: i64, limit: i64) -> Self {
        self.pod = self.pod.memory(requested as u32, limit as u32);
        self
    }

    /// Set CPU request and limit (in millicores)
    /// Note: Not yet implemented in the underlying fluent API
    #[allow(deprecated)]
    pub fn cpu(mut self, requested: i64, limit: i64) -> Self {
        self.pod = self.pod.cpu(requested as u32, limit as u32);
        self
    }

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

    /// Alias for apply (since `do` is reserved in Rhai)
    pub fn do_(&self) -> Result<(), Box<EvalAltResult>> {
        self.apply()
    }
}

// ============================================================================
// Service Wrapper
// ============================================================================

/// Rhai wrapper for ServiceBuilder
#[derive(Clone)]
pub struct ServiceRhai {
    service: ServiceBuilder,
}

impl ServiceRhai {
    /// Create a new ServiceRhai wrapper
    pub fn new(service: ServiceBuilder) -> Self {
        Self { service }
    }

    /// Set service selector
    pub fn selector(mut self, key: &str, value: &str) -> Self {
        self.service = self.service.selector(key, value);
        self
    }

    /// Expose a port
    pub fn expose(mut self, port: i64) -> Self {
        self.service = self.service.expose(port as u16);
        self
    }

    /// Set target container port
    pub fn to_container(mut self, port: i64) -> Self {
        self.service = self.service.to_container(port as u16);
        self
    }

    /// Alias for to_container
    pub fn to(mut self, port: i64) -> Self {
        self.service = self.service.to(port as u16);
        self
    }

    /// Set service type to NodePort
    /// Note: Not yet implemented in the underlying fluent API
    #[allow(deprecated)]
    pub fn nodeport(mut self) -> Self {
        self.service = self.service.nodeport();
        self
    }

    /// Set node port for NodePort service type
    /// Note: Not yet implemented in the underlying fluent API
    #[allow(deprecated)]
    pub fn via_node(mut self, node_port: i64) -> Self {
        self.service = self.service.via_node(&node_port.to_string());
        self
    }

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

    /// Alias for apply (since `do` is reserved in Rhai)
    pub fn do_(&self) -> Result<(), Box<EvalAltResult>> {
        self.apply()
    }
}

// ============================================================================
// Deployment Wrapper
// ============================================================================

/// Rhai wrapper for DeploymentBuilder
#[derive(Clone)]
pub struct DeploymentRhai {
    deployment: DeploymentBuilder,
}

impl DeploymentRhai {
    /// Create a new DeploymentRhai wrapper
    pub fn new(deployment: DeploymentBuilder) -> Self {
        Self { deployment }
    }

    /// Set the image
    pub fn image(mut self, image: &str) -> Self {
        self.deployment = self.deployment.image(image);
        self
    }

    /// Set the number of replicas
    pub fn replicas(mut self, replicas: i64) -> Self {
        self.deployment = self.deployment.replicas(replicas as i32);
        self
    }

    /// Set environment variable
    pub fn env(mut self, key: &str, value: &str) -> Self {
        self.deployment = self.deployment.env(key, value);
        self
    }

    /// Add a label
    pub fn label(mut self, key: &str, value: &str) -> Self {
        self.deployment = self.deployment.label(key, value);
        self
    }

    /// Add a port
    pub fn port(mut self, port: i64) -> Self {
        self.deployment = self.deployment.port(port as u16);
        self
    }

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

    /// Alias for apply (since `do` is reserved in Rhai)
    pub fn do_(&self) -> Result<(), Box<EvalAltResult>> {
        self.apply()
    }
}
