//! Rhai wrapper for DevelopmentMachine (Kubernetes pod with SSH access)

use crate::kubernetes::DevelopmentMachine;
use rhai::EvalAltResult;
use super::runtime::{get_runtime, to_rhai_err};

/// Rhai wrapper for DevelopmentMachine builder
#[derive(Clone)]
pub struct DevelopmentMachineRhai {
    dev: DevelopmentMachine,
}

impl DevelopmentMachineRhai {
    /// Create a new DevelopmentMachineRhai wrapper
    pub fn new(dev: DevelopmentMachine) -> Self {
        Self { dev }
    }

    /// Sets the namespace (default: "development").
    pub fn namespace(mut self, namespace: &str) -> Self {
        self.dev = self.dev.namespace(namespace);
        self
    }

    /// Sets the Docker image (default: "ubuntu:22.04").
    pub fn image(mut self, image: &str) -> Self {
        self.dev = self.dev.image(image);
        self
    }

    /// Sets CPU resources in millicores (request, limit).
    /// 1000 = 1 core (default: 500m request, 500m limit)
    pub fn cpu(mut self, request: i64, limit: i64) -> Self {
        self.dev = self.dev.cpu(request as u32, limit as u32);
        self
    }

    /// Sets memory resources in MB (request, limit).
    /// (default: 1024 MB request, 1024 MB limit)
    pub fn memory(mut self, request: i64, limit: i64) -> Self {
        self.dev = self.dev.memory(request as u32, limit as u32);
        self
    }

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

    /// Adds all ConfigMap values as environment variables.
    pub fn env_from_configmap(mut self, configmap: &str) -> Self {
        self.dev = self.dev.env_from_configmap(configmap);
        self
    }

    /// Adds all Secret values as environment variables.
    pub fn env_from_secret(mut self, secret: &str) -> Self {
        self.dev = self.dev.env_from_secret(secret);
        self
    }

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

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

    /// Sets HTTP readiness probe.
    /// Returns false if probe fails - pod won't receive traffic.
    pub fn readiness_http(mut self, path: &str, port: i64) -> Self {
        self.dev = self.dev.readiness_http(path, port as u16);
        self
    }

    /// Sets HTTP liveness probe.
    /// Pod is restarted if probe fails (default: initial_delay=0, period=10, failure_threshold=3)
    pub fn liveness_http(mut self, path: &str, port: i64) -> Self {
        self.dev = self.dev.liveness_http(path, port as u16);
        self
    }

    /// Sets TCP readiness probe on specified port.
    pub fn readiness_tcp(mut self, port: i64) -> Self {
        self.dev = self.dev.readiness_tcp(port as u16);
        self
    }

    /// Sets TCP liveness probe on specified port.
    /// Pod is restarted if probe fails (default: initial_delay=0, period=10, failure_threshold=3)
    pub fn liveness_tcp(mut self, port: i64) -> Self {
        self.dev = self.dev.liveness_tcp(port as u16);
        self
    }

    /// Sets initial delay for liveness probe in seconds.
    pub fn initial_delay(mut self, seconds: i64) -> Self {
        self.dev = self.dev.initial_delay(seconds as u32);
        self
    }

    /// Sets period for liveness probe in seconds.
    pub fn period(mut self, seconds: i64) -> Self {
        self.dev = self.dev.period(seconds as u32);
        self
    }

    /// Sets failure threshold for liveness probe.
    pub fn failure_threshold(mut self, count: i64) -> Self {
        self.dev = self.dev.failure_threshold(count as u32);
        self
    }

    /// Sets restart policy: "always", "onfail", or "never".
    /// Default: "always"
    pub fn restart(mut self, policy: &str) -> Self {
        self.dev = self.dev.restart(policy);
        self
    }

    /// If set to true, will delete and recreate the pod (default: false).
    pub fn reset(mut self, reset: bool) -> Self {
        self.dev = self.dev.reset(reset);
        self
    }

    /// Sets the secret name for SSH keys (default: "{name}-ssh-keys").
    pub fn secret_name(mut self, secret_name: &str) -> Self {
        self.dev = self.dev.secret_name(secret_name);
        self
    }

    /// Deploys the development machine pod with SSH access enabled.
    /// Returns self with the deployed pod information.
    pub fn deploy(&self) -> Result<DevelopmentMachineRhai, Box<EvalAltResult>> {
        let dev = self.dev.clone();
        let rt = get_runtime();
        let deployed = rt.block_on(async {
            tokio::task::block_in_place(|| {
                dev.deploy().map_err(|e| format!("Deploy error: {}", e))
            })
        })
        .map_err(|e| to_rhai_err(e))?;

        Ok(DevelopmentMachineRhai::new(deployed))
    }

    /// Gets the private SSH key for the development machine.
    pub fn get_ssh_key(&self) -> Result<String, Box<EvalAltResult>> {
        self.dev
            .get_ssh_key()
            .map_err(|e| to_rhai_err(format!("Get SSH key error: {}", e)))
    }

    /// Gets the public SSH key for the development machine.
    pub fn get_ssh_public_key(&self) -> Result<String, Box<EvalAltResult>> {
        self.dev
            .get_ssh_public_key()
            .map_err(|e| to_rhai_err(format!("Get SSH public key error: {}", e)))
    }

    /// Gets the name of the development machine (pod name).
    pub fn get_name(&self) -> String {
        self.dev.get_name().to_string()
    }

    /// Gets the namespace of the development machine.
    pub fn get_namespace(&self) -> String {
        self.dev.get_namespace().to_string()
    }

    /// Gets the Docker image of the development machine.
    pub fn get_image(&self) -> String {
        self.dev.get_image().to_string()
    }
}
