use crate::cloudhv::config::{CloudHypervisorConfig, VMConfig, VMSpec, ConsoleMode, SerialMode};
use crate::cloudhv::errors::{CloudHypervisorError, Result};
use crate::cloudhv::runtime::{CloudHypervisorRuntime, VMHandle};
use rhai::{Dynamic, Engine, AST, EvalAltResult};
use std::path::PathBuf;
use std::sync::{Arc, Mutex};
use once_cell::sync::Lazy;

// Global runtime state for herodo integration
static GLOBAL_RUNTIME: Lazy<Arc<Mutex<Option<Arc<CloudHypervisorRuntime>>>>> = 
    Lazy::new(|| Arc::new(Mutex::new(None)));

/// Register Cloud Hypervisor types and functions with the Rhai engine
pub fn register_cloudhv_module(engine: &mut Engine) -> std::result::Result<(), Box<EvalAltResult>> {
    engine
        .register_type::<RuntimeBuilder>()
        .register_fn("RuntimeBuilder", RuntimeBuilder::new)
        .register_fn("ch_path", RuntimeBuilder::ch_path)
        .register_fn("api_socket", RuntimeBuilder::api_socket)
        .register_fn("log_file", RuntimeBuilder::log_file)
        .register_fn("seccomp", RuntimeBuilder::seccomp)
        .register_fn("landlock", RuntimeBuilder::landlock)
        .register_fn("start", RuntimeBuilder::start);

    engine
        .register_type::<VMBuilder>()
        .register_fn("VMBuilder", VMBuilder::new)
        .register_fn("kernel", VMBuilder::kernel)
        .register_fn("initramfs", VMBuilder::initramfs)
        .register_fn("cmdline", VMBuilder::cmdline)
        .register_fn("cmdline", VMBuilder::cmdline_string)
        .register_fn("memory", VMBuilder::memory)
        .register_fn("memory_shared", VMBuilder::memory_shared)
        .register_fn("cpus", VMBuilder::cpus)
        .register_fn("virtio_blk", VMBuilder::virtio_blk)
        .register_fn("virtio_net", VMBuilder::virtio_net)
        .register_fn("virtio_net_with_mac", VMBuilder::virtio_net_with_mac)
        .register_fn("virtio_rng", VMBuilder::virtio_rng)
        .register_fn("virtio_fs", VMBuilder::virtio_fs)
        .register_fn("vhost_user_net", VMBuilder::vhost_user_net)
        .register_fn("vhost_user_blk", VMBuilder::vhost_user_blk)
        .register_fn("vfio", VMBuilder::vfio)
        .register_fn("console", VMBuilder::console)
        .register_fn("serial", VMBuilder::serial)
        .register_fn("build", VMBuilder::build);

    engine
        .register_type::<DeviceBuilder>()
        .register_fn("DeviceBuilder", DeviceBuilder::new)
        .register_fn("disk", DeviceBuilder::disk)
        .register_fn("net", DeviceBuilder::net)
        .register_fn("net_with_mac", DeviceBuilder::net_with_mac)
        .register_fn("fs", DeviceBuilder::fs)
        .register_fn("vhost_user_net", DeviceBuilder::vhost_user_net)
        .register_fn("vhost_user_blk", DeviceBuilder::vhost_user_blk);

    engine
        .register_type::<VMSpec>()
        .register_get("id", |spec: &mut VMSpec| spec.id.clone());

    engine
        .register_type::<VMHandle>()
        .register_get("id", |handle: &mut VMHandle| handle.id.clone());

    engine.register_fn("sleep", |ms: i64| {
        std::thread::sleep(std::time::Duration::from_millis(ms as u64));
    });

    // Register init_runtime function
    engine.register_fn("init_runtime", |builder: RuntimeBuilder| -> bool {
        let rt = builder.build_and_start();
        match rt {
            Ok(r) => {
                *GLOBAL_RUNTIME.lock().unwrap() = Some(Arc::new(r));
                true
            }
            Err(e) => {
                eprintln!("\n❌ ERROR: Failed to initialize runtime");
                eprintln!("   {}", e);
                eprintln!("\n   Script execution will continue but all VM operations will fail.");
                eprintln!("   Please fix the error and try again.\n");
                false
            }
        }
    });

    // Register VM operation functions
    engine.register_fn("create_vm", |spec: VMSpec| -> VMHandle {
        let runtime = match GLOBAL_RUNTIME.lock().unwrap().clone() {
            Some(rt) => rt,
            None => {
                panic!("Runtime not initialized. Call init_runtime() first.");
            }
        };
        let handle = if tokio::runtime::Handle::try_current().is_ok() {
            tokio::task::block_in_place(|| {
                tokio::runtime::Handle::current().block_on(async {
                    runtime.create_vm(spec).await
                })
            })
        } else {
            tokio::runtime::Runtime::new()
                .unwrap()
                .block_on(async { runtime.create_vm(spec).await })
        };
        match handle {
            Ok(h) => h,
            Err(e) => {
                panic!("Failed to create VM: {}", e);
            }
        }
    });

    engine.register_fn("start_vm", |handle: VMHandle| {
        let runtime = match GLOBAL_RUNTIME.lock().unwrap().clone() {
            Some(rt) => rt,
            None => {
                panic!("Runtime not initialized. Call init_runtime() first.");
            }
        };
        let result = if tokio::runtime::Handle::try_current().is_ok() {
            tokio::task::block_in_place(|| {
                tokio::runtime::Handle::current().block_on(async {
                    runtime.start_vm(&handle).await
                })
            })
        } else {
            tokio::runtime::Runtime::new()
                .unwrap()
                .block_on(async { runtime.start_vm(&handle).await })
        };
        match result {
            Ok(_) => {},
            Err(e) => panic!("Failed to start VM: {}", e),
        }
    });

    engine.register_fn("stop_vm", |handle: VMHandle| {
        let runtime = match GLOBAL_RUNTIME.lock().unwrap().clone() {
            Some(rt) => rt,
            None => {
                panic!("Runtime not initialized. Call init_runtime() first.");
            }
        };
        let result = if tokio::runtime::Handle::try_current().is_ok() {
            tokio::task::block_in_place(|| {
                tokio::runtime::Handle::current().block_on(async {
                    runtime.stop_vm(&handle, false).await
                })
            })
        } else {
            tokio::runtime::Runtime::new()
                .unwrap()
                .block_on(async { runtime.stop_vm(&handle, false).await })
        };
        match result {
            Ok(_) => {},
            Err(e) => panic!("Failed to stop VM: {}", e),
        }
    });

    engine.register_fn("pause_vm", |handle: VMHandle| {
        let runtime = match GLOBAL_RUNTIME.lock().unwrap().clone() {
            Some(rt) => rt,
            None => {
                panic!("Runtime not initialized. Call init_runtime() first.");
            }
        };
        let result = if tokio::runtime::Handle::try_current().is_ok() {
            tokio::task::block_in_place(|| {
                tokio::runtime::Handle::current().block_on(async {
                    runtime.pause_vm(&handle).await
                })
            })
        } else {
            tokio::runtime::Runtime::new()
                .unwrap()
                .block_on(async { runtime.pause_vm(&handle).await })
        };
        match result {
            Ok(_) => {},
            Err(e) => panic!("Failed to pause VM: {}", e),
        }
    });

    engine.register_fn("resume_vm", |handle: VMHandle| {
        let runtime = match GLOBAL_RUNTIME.lock().unwrap().clone() {
            Some(rt) => rt,
            None => {
                panic!("Runtime not initialized. Call init_runtime() first.");
            }
        };
        let result = if tokio::runtime::Handle::try_current().is_ok() {
            tokio::task::block_in_place(|| {
                tokio::runtime::Handle::current().block_on(async {
                    runtime.resume_vm(&handle).await
                })
            })
        } else {
            tokio::runtime::Runtime::new()
                .unwrap()
                .block_on(async { runtime.resume_vm(&handle).await })
        };
        match result {
            Ok(_) => {},
            Err(e) => panic!("Failed to resume VM: {}", e),
        }
    });

    engine.register_fn("reset_vm", |handle: VMHandle| {
        let runtime = match GLOBAL_RUNTIME.lock().unwrap().clone() {
            Some(rt) => rt,
            None => {
                panic!("Runtime not initialized. Call init_runtime() first.");
            }
        };
        let result = if tokio::runtime::Handle::try_current().is_ok() {
            tokio::task::block_in_place(|| {
                tokio::runtime::Handle::current().block_on(async {
                    runtime.reset_vm(&handle).await
                })
            })
        } else {
            tokio::runtime::Runtime::new()
                .unwrap()
                .block_on(async { runtime.reset_vm(&handle).await })
        };
        match result {
            Ok(_) => {},
            Err(e) => panic!("Failed to reset VM: {}", e),
        }
    });

    engine.register_fn("get_vm_status", |handle: VMHandle| -> String {
        let runtime = match GLOBAL_RUNTIME.lock().unwrap().clone() {
            Some(rt) => rt,
            None => {
                eprintln!("Runtime not initialized. Call init_runtime() first.");
                return "NotInitialized".to_string();
            }
        };
        let status = if tokio::runtime::Handle::try_current().is_ok() {
            tokio::task::block_in_place(|| {
                tokio::runtime::Handle::current().block_on(async {
                    runtime.get_vm_status(&handle).await
                })
            })
        } else {
            tokio::runtime::Runtime::new()
                .unwrap()
                .block_on(async { runtime.get_vm_status(&handle).await })
        };
        match status {
            Ok(s) => format!("{:?}", s),
            Err(_) => "Unknown".to_string(),
        }
    });

    Ok(())
}

pub struct ScriptEngine {
    engine: Engine,
    runtime: Arc<Mutex<Option<Arc<CloudHypervisorRuntime>>>>,
}

impl ScriptEngine {
    pub fn new() -> Self {
        let mut engine = Engine::new();
        let runtime = Arc::new(Mutex::new(None));

        register_cloudhv_module(&mut engine).expect("Failed to register cloudhv module");

        let runtime_clone = Arc::clone(&runtime);
        engine.register_fn("init_runtime", move |builder: RuntimeBuilder| -> bool {
            let rt = builder.build_and_start();
            match rt {
                Ok(r) => {
                    *runtime_clone.lock().unwrap() = Some(Arc::new(r));
                    true
                }
                Err(e) => {
                    eprintln!("\n❌ ERROR: Failed to initialize runtime");
                    eprintln!("   {}", e);
                    eprintln!("\n   Script execution will continue but all VM operations will fail.");
                    eprintln!("   Please fix the error and try again.\n");
                    false
                }
            }
        });

        Self { engine, runtime }
    }

    pub fn new_with_runtime(runtime: Arc<CloudHypervisorRuntime>) -> Self {
        let mut engine = Engine::new();
        let runtime_wrapper = Arc::new(Mutex::new(Some(runtime)));

        engine
            .register_type::<RuntimeBuilder>()
            .register_fn("RuntimeBuilder", RuntimeBuilder::new)
            .register_fn("ch_path", RuntimeBuilder::ch_path)
            .register_fn("api_socket", RuntimeBuilder::api_socket)
            .register_fn("log_file", RuntimeBuilder::log_file)
            .register_fn("seccomp", RuntimeBuilder::seccomp)
            .register_fn("landlock", RuntimeBuilder::landlock)
            .register_fn("start", RuntimeBuilder::start);

        let runtime_clone = Arc::clone(&runtime_wrapper);
        engine.register_fn("init_runtime", move |builder: RuntimeBuilder| -> bool {
            let rt = builder.build_and_start();
            match rt {
                Ok(r) => {
                    *runtime_clone.lock().unwrap() = Some(Arc::new(r));
                    true
                }
                Err(e) => {
                    eprintln!("\n❌ ERROR: Failed to initialize runtime");
                    eprintln!("   {}", e);
                    eprintln!("\n   Script execution will continue but all VM operations will fail.");
                    eprintln!("   Please fix the error and try again.\n");
                    false
                }
            }
        });

        Self { engine, runtime: runtime_wrapper }
    }

    pub fn eval_script(&mut self, script: &str) -> Result<Dynamic> {

        let runtime_ref = Arc::clone(&self.runtime);
        self.engine.register_fn("create_vm", move |spec: VMSpec| {
            let runtime = match runtime_ref.lock().unwrap().clone() {
                Some(rt) => rt,
                None => {
                    panic!("Runtime not initialized. Call init_runtime() first.");
                }
            };
            let handle = if tokio::runtime::Handle::try_current().is_ok() {
                // Already in async context, use Handle
                tokio::task::block_in_place(|| {
                    tokio::runtime::Handle::current().block_on(async {
                        runtime.create_vm(spec).await
                    })
                })
            } else {
                // Not in async context, create new runtime
                tokio::runtime::Runtime::new()
                    .unwrap()
                    .block_on(async { runtime.create_vm(spec).await })
            };
            match handle {
                Ok(h) => h,
                Err(e) => {
                    panic!("Failed to create VM: {}", e);
                }
            }
        });

        let runtime_ref = Arc::clone(&self.runtime);
        self.engine.register_fn("start_vm", move |handle: VMHandle| {
            let runtime = match runtime_ref.lock().unwrap().clone() {
                Some(rt) => rt,
                None => {
                    panic!("Runtime not initialized. Call init_runtime() first.");
                }
            };
            let result = if tokio::runtime::Handle::try_current().is_ok() {
                tokio::task::block_in_place(|| {
                    tokio::runtime::Handle::current().block_on(async {
                        runtime.start_vm(&handle).await
                    })
                })
            } else {
                tokio::runtime::Runtime::new()
                    .unwrap()
                    .block_on(async { runtime.start_vm(&handle).await })
            };
            match result {
                Ok(_) => {},
                Err(e) => panic!("Failed to start VM: {}", e),
            }
        });

        let runtime_ref = Arc::clone(&self.runtime);
        self.engine.register_fn("stop_vm", move |handle: VMHandle| {
            let runtime = match runtime_ref.lock().unwrap().clone() {
                Some(rt) => rt,
                None => {
                    panic!("Runtime not initialized. Call init_runtime() first.");
                }
            };
            let result = if tokio::runtime::Handle::try_current().is_ok() {
                tokio::task::block_in_place(|| {
                    tokio::runtime::Handle::current().block_on(async {
                        runtime.stop_vm(&handle, false).await
                    })
                })
            } else {
                tokio::runtime::Runtime::new()
                    .unwrap()
                    .block_on(async { runtime.stop_vm(&handle, false).await })
            };
            match result {
                Ok(_) => {},
                Err(e) => panic!("Failed to stop VM: {}", e),
            }
        });

        let runtime_ref = Arc::clone(&self.runtime);
        self.engine.register_fn("pause_vm", move |handle: VMHandle| {
            let runtime = match runtime_ref.lock().unwrap().clone() {
                Some(rt) => rt,
                None => {
                    panic!("Runtime not initialized. Call init_runtime() first.");
                }
            };
            let result = if tokio::runtime::Handle::try_current().is_ok() {
                tokio::task::block_in_place(|| {
                    tokio::runtime::Handle::current().block_on(async {
                        runtime.pause_vm(&handle).await
                    })
                })
            } else {
                tokio::runtime::Runtime::new()
                    .unwrap()
                    .block_on(async { runtime.pause_vm(&handle).await })
            };
            match result {
                Ok(_) => {},
                Err(e) => panic!("Failed to pause VM: {}", e),
            }
        });

        let runtime_ref = Arc::clone(&self.runtime);
        self.engine.register_fn("resume_vm", move |handle: VMHandle| {
            let runtime = match runtime_ref.lock().unwrap().clone() {
                Some(rt) => rt,
                None => {
                    panic!("Runtime not initialized. Call init_runtime() first.");
                }
            };
            let result = if tokio::runtime::Handle::try_current().is_ok() {
                tokio::task::block_in_place(|| {
                    tokio::runtime::Handle::current().block_on(async {
                        runtime.resume_vm(&handle).await
                    })
                })
            } else {
                tokio::runtime::Runtime::new()
                    .unwrap()
                    .block_on(async { runtime.resume_vm(&handle).await })
            };
            match result {
                Ok(_) => {},
                Err(e) => panic!("Failed to resume VM: {}", e),
            }
        });

        let runtime_ref = Arc::clone(&self.runtime);
        self.engine.register_fn("get_vm_status", move || -> String {
            let runtime = match runtime_ref.lock().unwrap().clone() {
                Some(rt) => rt,
                None => {
                    eprintln!("Runtime not initialized. Call init_runtime() first.");
                    return "NotInitialized".to_string();
                }
            };
            let result = if tokio::runtime::Handle::try_current().is_ok() {
                tokio::task::block_in_place(|| {
                    tokio::runtime::Handle::current().block_on(async {
                        match runtime.get_api_client() {
                            Ok(client) => {
                                match client.vm_info().await {
                                    Ok(info) => info.state,
                                    Err(e) => {
                                        eprintln!("VM info error: {}", e);
                                        "Unknown".to_string()
                                    }
                                }
                            }
                            Err(e) => {
                                eprintln!("API client error: {}", e);
                                "NoAPI".to_string()
                            }
                        }
                    })
                })
            } else {
                tokio::runtime::Runtime::new()
                    .unwrap()
                    .block_on(async {
                        match runtime.get_api_client() {
                            Ok(client) => {
                                match client.vm_info().await {
                                    Ok(info) => info.state,
                                    Err(e) => {
                                        eprintln!("VM info error: {}", e);
                                        "Unknown".to_string()
                                    }
                                }
                            }
                            Err(e) => {
                                eprintln!("API client error: {}", e);
                                "NoAPI".to_string()
                            }
                        }
                    })
            };
            result
        });

        let runtime_ref = Arc::clone(&self.runtime);
        self.engine
            .register_fn("snapshot", move |handle: VMHandle, path: String| {
                let runtime = match runtime_ref.lock().unwrap().clone() {
                    Some(rt) => rt,
                    None => {
                        panic!("Runtime not initialized. Call init_runtime() first.");
                    }
                };
                let snapshot_path = PathBuf::from(path);
                let result = if tokio::runtime::Handle::try_current().is_ok() {
                    tokio::task::block_in_place(|| {
                        tokio::runtime::Handle::current().block_on(async {
                            runtime.create_snapshot(&handle, &snapshot_path).await
                        })
                    })
                } else {
                    tokio::runtime::Runtime::new()
                        .unwrap()
                        .block_on(async { runtime.create_snapshot(&handle, &snapshot_path).await })
                };
                match result {
                    Ok(_) => {},
                    Err(e) => panic!("Failed to create snapshot: {}", e),
                }
            });

        let runtime_ref = Arc::clone(&self.runtime);
        self.engine.register_fn("restore", move |path: String| {
            let runtime = match runtime_ref.lock().unwrap().clone() {
                Some(rt) => rt,
                None => {
                    panic!("Runtime not initialized. Call init_runtime() first.");
                }
            };
            let snapshot_path = PathBuf::from(path);
            let result = if tokio::runtime::Handle::try_current().is_ok() {
                tokio::task::block_in_place(|| {
                    tokio::runtime::Handle::current().block_on(async {
                        runtime.restore_snapshot(&snapshot_path).await
                    })
                })
            } else {
                tokio::runtime::Runtime::new()
                    .unwrap()
                    .block_on(async { runtime.restore_snapshot(&snapshot_path).await })
            };
            match result {
                Ok(handle) => handle,
                Err(e) => {
                    panic!("Failed to restore snapshot: {}", e);
                }
            }
        });

        // Reset VM
        let runtime_ref = Arc::clone(&self.runtime);
        self.engine.register_fn("reset_vm", move |handle: VMHandle| {
            let runtime = match runtime_ref.lock().unwrap().clone() {
                Some(rt) => rt,
                None => {
                    panic!("Runtime not initialized. Call init_runtime() first.");
                }
            };
            let result = if tokio::runtime::Handle::try_current().is_ok() {
                tokio::task::block_in_place(|| {
                    tokio::runtime::Handle::current().block_on(async {
                        runtime.reset_vm(&handle).await
                    })
                })
            } else {
                tokio::runtime::Runtime::new()
                    .unwrap()
                    .block_on(async { runtime.reset_vm(&handle).await })
            };
            match result {
                Ok(_) => {},
                Err(e) => panic!("Failed to reset VM: {}", e),
            }
        });

        // Resize memory (hot-add)
        let runtime_ref = Arc::clone(&self.runtime);
        self.engine
            .register_fn("resize_memory", move |handle: VMHandle, size_mb: i64| {
                let runtime = match runtime_ref.lock().unwrap().clone() {
                    Some(rt) => rt,
                    None => {
                        panic!("Runtime not initialized. Call init_runtime() first.");
                    }
                };
                let result = if tokio::runtime::Handle::try_current().is_ok() {
                    tokio::task::block_in_place(|| {
                        tokio::runtime::Handle::current().block_on(async {
                            runtime.resize_memory(&handle, size_mb as u64).await
                        })
                    })
                } else {
                    tokio::runtime::Runtime::new().unwrap().block_on(async {
                        runtime.resize_memory(&handle, size_mb as u64).await
                    })
                };
                match result {
                    Ok(_) => {},
                    Err(e) => panic!("Failed to resize memory: {}", e),
                }
            });

        // Add vCPU (hot-add)
        let runtime_ref = Arc::clone(&self.runtime);
        self.engine
            .register_fn("add_vcpu", move |handle: VMHandle, count: i64| {
                let runtime = match runtime_ref.lock().unwrap().clone() {
                    Some(rt) => rt,
                    None => {
                        panic!("Runtime not initialized. Call init_runtime() first.");
                    }
                };
                let result = if tokio::runtime::Handle::try_current().is_ok() {
                    tokio::task::block_in_place(|| {
                        tokio::runtime::Handle::current().block_on(async {
                            runtime.add_vcpu(&handle, count as u32).await
                        })
                    })
                } else {
                    tokio::runtime::Runtime::new()
                        .unwrap()
                        .block_on(async { runtime.add_vcpu(&handle, count as u32).await })
                };
                match result {
                    Ok(_) => {},
                    Err(e) => panic!("Failed to add vCPU: {}", e),
                }
            });

        // List snapshots
        let runtime_ref = Arc::clone(&self.runtime);
        self.engine.register_fn("list_snapshots", move |vm_id: String| -> Vec<Dynamic> {
            let runtime = match runtime_ref.lock().unwrap().clone() {
                Some(rt) => rt,
                None => {
                    eprintln!("Runtime not initialized. Call init_runtime() first.");
                    return vec![];
                }
            };
            match runtime.list_snapshots(&vm_id) {
                Ok(snapshots) => {
                    snapshots.into_iter().map(|s| {
                        let mut map = rhai::Map::new();
                        map.insert("vm_id".into(), Dynamic::from(s.vm_id));
                        map.insert("name".into(), Dynamic::from(s.name));
                        map.insert("path".into(), Dynamic::from(s.path.to_string_lossy().to_string()));
                        map.insert("timestamp".into(), Dynamic::from(s.timestamp));
                        map.insert("size".into(), Dynamic::from(s.size as i64));
                        Dynamic::from(map)
                    }).collect()
                }
                Err(e) => {
                    eprintln!("Failed to list snapshots: {}", e);
                    vec![]
                }
            }
        });

        // Delete snapshot
        let runtime_ref = Arc::clone(&self.runtime);
        self.engine.register_fn("delete_snapshot", move |vm_id: String, name: String| {
            let runtime = match runtime_ref.lock().unwrap().clone() {
                Some(rt) => rt,
                None => {
                    eprintln!("Runtime not initialized. Call init_runtime() first.");
                    return false;
                }
            };
            runtime.delete_snapshot(&vm_id, &name).is_ok()
        });

        // Add device (hot-plug)
        let runtime_ref = Arc::clone(&self.runtime);
        self.engine.register_fn("add_device", move |handle: VMHandle, builder: DeviceBuilder| -> String {
            let runtime = match runtime_ref.lock().unwrap().clone() {
                Some(rt) => rt,
                None => {
                    panic!("Runtime not initialized. Call init_runtime() first.");
                }
            };
            
            use crate::cloudhv::config::{DeviceConfig, DeviceType, DiskConfig, NetConfig, FsConfig, VhostUserNetConfig, VhostUserBlkConfig};
            use std::path::PathBuf;
            
            let device_type = match builder.get_type().as_str() {
                "disk" => {
                    let config = builder.get_config();
                    let path = config.get("path").and_then(|v| v.clone().into_string().ok()).unwrap_or_default();
                    let readonly = config.get("readonly").and_then(|v| v.as_bool().ok()).unwrap_or(false);
                    DeviceType::Disk(DiskConfig {
                        path: PathBuf::from(path),
                        readonly,
                        direct: false,
                        vhost_user: false,
                        socket: None,
                    })
                }
                "net" => {
                    let config = builder.get_config();
                    let tap = config.get("tap").and_then(|v| v.clone().into_string().ok());
                    let mac = config.get("mac").and_then(|v| v.clone().into_string().ok());
                    DeviceType::Net(NetConfig {
                        tap,
                        mac,
                        vhost_user: false,
                        socket: None,
                    })
                }
                "fs" => {
                    let config = builder.get_config();
                    let tag = config.get("tag").and_then(|v| v.clone().into_string().ok()).unwrap_or_default();
                    let socket = config.get("socket").and_then(|v| v.clone().into_string().ok()).unwrap_or_default();
                    DeviceType::Fs(FsConfig {
                        tag,
                        socket: PathBuf::from(socket),
                        num_queues: 1,
                        cache_size: 8589934592, // 8GB default
                        queue_size: 1024,
                    })
                }
                "vhost_user_net" => {
                    let config = builder.get_config();
                    let socket = config.get("socket").and_then(|v| v.clone().into_string().ok()).unwrap_or_default();
                    DeviceType::VhostUserNet(VhostUserNetConfig {
                        socket: PathBuf::from(socket),
                        mac: None,
                        num_queues: 2,
                        queue_size: 256,
                    })
                }
                "vhost_user_blk" => {
                    let config = builder.get_config();
                    let socket = config.get("socket").and_then(|v| v.clone().into_string().ok()).unwrap_or_default();
                    let readonly = config.get("readonly").and_then(|v| v.as_bool().ok()).unwrap_or(false);
                    DeviceType::VhostUserBlk(VhostUserBlkConfig {
                        socket: PathBuf::from(socket),
                        num_queues: 1,
                        queue_size: 128,
                        readonly,
                    })
                }
                _ => {
                    eprintln!("Unknown device type: {}", builder.get_type());
                    return "error".to_string();
                }
            };
            
            let device = DeviceConfig {
                id: builder.get_id(),
                device_type,
            };
            
            let result = if tokio::runtime::Handle::try_current().is_ok() {
                tokio::task::block_in_place(|| {
                    tokio::runtime::Handle::current().block_on(async {
                        runtime.add_device(&handle, device).await
                    })
                })
            } else {
                tokio::runtime::Runtime::new()
                    .unwrap()
                    .block_on(async { runtime.add_device(&handle, device).await })
            };
            
            match result {
                Ok(id) => id,
                Err(e) => {
                    panic!("Failed to add device: {}", e);
                }
            }
        });

        // Remove device (hot-unplug)
        let runtime_ref = Arc::clone(&self.runtime);
        self.engine
            .register_fn("remove_device", move |handle: VMHandle, device_id: String| {
                let runtime = match runtime_ref.lock().unwrap().clone() {
                    Some(rt) => rt,
                    None => {
                        panic!("Runtime not initialized. Call init_runtime() first.");
                    }
                };
                let result = if tokio::runtime::Handle::try_current().is_ok() {
                    tokio::task::block_in_place(|| {
                        tokio::runtime::Handle::current().block_on(async {
                            runtime.remove_device(&handle, &device_id).await
                        })
                    })
                } else {
                    tokio::runtime::Runtime::new()
                        .unwrap()
                        .block_on(async { runtime.remove_device(&handle, &device_id).await })
                };
                match result {
                    Ok(_) => {},
                    Err(e) => panic!("Failed to remove device: {}", e),
                }
            });

        self.engine
            .eval::<Dynamic>(script)
            .map_err(|e| CloudHypervisorError::Script(format!("Script error: {}", e)))
    }

    pub fn compile_script(&self, script: &str) -> Result<AST> {
        self.engine
            .compile(script)
            .map_err(|e| CloudHypervisorError::Script(format!("Compilation error: {}", e)))
    }

    pub fn eval_ast(&mut self, ast: &AST) -> Result<Dynamic> {
        self.engine
            .eval_ast::<Dynamic>(ast)
            .map_err(|e| CloudHypervisorError::Script(format!("Execution error: {}", e)))
    }
}

#[derive(Clone)]
pub struct VMBuilder {
    config: VMConfig,
}

impl VMBuilder {
    pub fn new() -> Self {
        Self {
            config: VMConfig::new(),
        }
    }

    pub fn kernel(mut self, path: String) -> Self {
        self.config = self.config.with_kernel(path);
        self
    }

    pub fn initramfs(mut self, path: String) -> Self {
        self.config = self.config.with_initramfs(path);
        self
    }

    pub fn cmdline(mut self, args: Vec<Dynamic>) -> Self {
        let string_args: Vec<String> = args
            .into_iter()
            .filter_map(|d| d.into_string().ok())
            .collect();
        self.config = self.config.with_cmdline(string_args);
        self
    }

    pub fn cmdline_string(mut self, cmdline: String) -> Self {
        let args: Vec<String> = cmdline.split_whitespace().map(|s| s.to_string()).collect();
        self.config = self.config.with_cmdline(args);
        self
    }

    pub fn memory(mut self, size_mb: i64) -> Self {
        self.config = self.config.with_memory(size_mb as u64);
        self
    }

    pub fn memory_shared(mut self, shared: bool) -> Self {
        self.config = self.config.with_memory_shared(shared);
        self
    }

    pub fn cpus(mut self, count: i64) -> Self {
        self.config = self.config.with_cpus(count as u32);
        self
    }

    pub fn virtio_blk(mut self, path: String, readonly: bool) -> Self {
        self.config.add_virtio_blk(path, readonly);
        self
    }

    pub fn virtio_net(mut self, tap: String) -> Self {
        self.config.add_virtio_net(tap);
        self
    }

    pub fn virtio_net_with_mac(mut self, tap: String, mac: String) -> Self {
        self.config.add_virtio_net_with_mac(tap, mac);
        self
    }

    pub fn virtio_rng(mut self) -> Self {
        self.config.add_virtio_rng();
        self
    }

    pub fn virtio_fs(mut self, tag: String, path: String) -> Self {
        self.config.add_virtio_fs(tag, path);
        self
    }

    pub fn vhost_user_net(mut self, socket: String) -> Self {
        self.config.add_vhost_user_net(socket);
        self
    }

    pub fn vhost_user_blk(mut self, socket: String) -> Self {
        self.config.add_vhost_user_blk(socket);
        self
    }

    pub fn vfio(mut self, device: String) -> Self {
        self.config.add_vfio(device);
        self
    }

    pub fn console(mut self, mode: String) -> Self {
        self.config.console.mode = match mode.as_str() {
            "tty" => ConsoleMode::Tty,
            "off" => ConsoleMode::Off,
            "file" => ConsoleMode::File,
            "null" => ConsoleMode::Null,
            _ => ConsoleMode::Off,
        };
        self
    }

    pub fn serial(mut self, mode: String) -> Self {
        self.config.serial.mode = match mode.as_str() {
            "tty" => SerialMode::Tty,
            "off" => SerialMode::Off,
            "file" => SerialMode::File,
            "null" => SerialMode::Null,
            _ => SerialMode::Null,
        };
        self
    }

    pub fn build(self) -> VMSpec {
        self.config.build().unwrap_or_else(|e| {
            eprintln!("Failed to build VM config: {}", e);
            VMSpec {
                config: VMConfig::default(),
                id: "error".to_string(),
            }
        })
    }
}

impl Default for VMBuilder {
    fn default() -> Self {
        Self::new()
    }
}

#[derive(Clone)]
pub struct RuntimeBuilder {
    ch_path: Option<String>,
    api_socket: String,
    log_file: Option<String>,
    seccomp: bool,
    landlock: bool,
}

impl RuntimeBuilder {
    pub fn new() -> Self {
        Self {
            ch_path: None, // Will use smart detection
            api_socket: "/tmp/ch-vm.sock".to_string(),
            log_file: None,
            seccomp: true,
            landlock: true,
        }
    }

    pub fn ch_path(mut self, path: String) -> Self {
        self.ch_path = Some(path);
        self
    }

    pub fn api_socket(mut self, path: String) -> Self {
        self.api_socket = path;
        self
    }

    pub fn log_file(mut self, path: String) -> Self {
        self.log_file = Some(path);
        self
    }

    pub fn seccomp(mut self, enabled: bool) -> Self {
        self.seccomp = enabled;
        self
    }

    pub fn landlock(mut self, enabled: bool) -> Self {
        self.landlock = enabled;
        self
    }

    pub fn start(self) -> Self {
        self
    }

    pub fn build_and_start(self) -> Result<CloudHypervisorRuntime> {
        // Use smart path resolution
        let mut config = CloudHypervisorConfig::new_smart(self.ch_path)?
            .with_api_socket(&self.api_socket)
            .with_seccomp(self.seccomp)
            .with_landlock(self.landlock);

        if let Some(log) = self.log_file {
            config = config.with_log_file(log);
        }

        let runtime = CloudHypervisorRuntime::new(config)?;
        runtime.start()?;
        Ok(runtime)
    }
}

impl Default for RuntimeBuilder {
    fn default() -> Self {
        Self::new()
    }
}

#[derive(Clone)]
pub struct DeviceBuilder {
    device_id: String,
    device_type: Option<String>,
    config: rhai::Map,
}

impl DeviceBuilder {
    pub fn new(id: String) -> Self {
        Self {
            device_id: id,
            device_type: None,
            config: rhai::Map::new(),
        }
    }

    pub fn disk(mut self, path: String, readonly: bool) -> Self {
        self.device_type = Some("disk".to_string());
        self.config.insert("path".into(), Dynamic::from(path));
        self.config.insert("readonly".into(), Dynamic::from(readonly));
        self
    }

    pub fn net(mut self, tap: String) -> Self {
        self.device_type = Some("net".to_string());
        self.config.insert("tap".into(), Dynamic::from(tap));
        self
    }

    pub fn net_with_mac(mut self, tap: String, mac: String) -> Self {
        self.device_type = Some("net".to_string());
        self.config.insert("tap".into(), Dynamic::from(tap));
        self.config.insert("mac".into(), Dynamic::from(mac));
        self
    }

    pub fn fs(mut self, tag: String, socket: String) -> Self {
        self.device_type = Some("fs".to_string());
        self.config.insert("tag".into(), Dynamic::from(tag));
        self.config.insert("socket".into(), Dynamic::from(socket));
        self
    }

    pub fn vhost_user_net(mut self, socket: String) -> Self {
        self.device_type = Some("vhost_user_net".to_string());
        self.config.insert("socket".into(), Dynamic::from(socket));
        self
    }

    pub fn vhost_user_blk(mut self, socket: String, readonly: bool) -> Self {
        self.device_type = Some("vhost_user_blk".to_string());
        self.config.insert("socket".into(), Dynamic::from(socket));
        self.config.insert("readonly".into(), Dynamic::from(readonly));
        self
    }

    pub fn get_id(&self) -> String {
        self.device_id.clone()
    }

    pub fn get_type(&self) -> String {
        self.device_type.clone().unwrap_or_default()
    }

    pub fn get_config(&self) -> rhai::Map {
        self.config.clone()
    }
}

impl Default for DeviceBuilder {
    fn default() -> Self {
        Self::new("device0".to_string())
    }
}
