use crate::cloudhv::config::*;
use crate::cloudhv::errors::CloudHypervisorError;
use std::path::PathBuf;

#[test]
fn test_vm_config_builder() {
    let config = VMConfig::new()
        .with_kernel("/boot/vmlinux")
        .with_cpus(4)
        .with_memory(2048);

    assert!(config.payload.is_some());
    assert_eq!(config.payload.as_ref().unwrap().kernel, Some("/boot/vmlinux".to_string()));
    assert_eq!(config.cpus.boot_vcpus, 4);
    assert_eq!(config.memory.size, 2048 * 1024 * 1024);
}

#[test]
fn test_vm_config_with_devices() {
    let mut config = VMConfig::new()
        .with_kernel("/boot/vmlinux")
        .with_cpus(2)
        .with_memory(1024);

    config.add_virtio_blk("/disk.img", false);
    config.add_virtio_net("tap0");

    assert_eq!(config.disks.len(), 1);
    assert_eq!(config.disks[0].path, PathBuf::from("/disk.img"));
    assert!(!config.disks[0].readonly);

    assert_eq!(config.net.len(), 1);
    assert_eq!(config.net[0].tap, Some("tap0".to_string()));
}

#[test]
fn test_vm_config_build_success() {
    let config = VMConfig::new()
        .with_kernel("/boot/vmlinux")
        .with_cpus(2)
        .with_memory(1024);

    let result = config.build();
    assert!(result.is_ok());

    let spec = result.unwrap();
    assert!(!spec.id.is_empty());
    assert_eq!(spec.config.cpus.boot_vcpus, 2);
}

#[test]
fn test_vm_config_build_no_kernel() {
    let config = VMConfig::new().with_cpus(2).with_memory(1024);

    let result = config.build();
    assert!(result.is_err());

    match result {
        Err(CloudHypervisorError::Config(msg)) => {
            assert!(msg.contains("Kernel path is required"));
        }
        _ => panic!("Expected Config error"),
    }
}

#[test]
fn test_vm_config_build_no_cpus() {
    let config = VMConfig::new().with_kernel("/boot/vmlinux").with_cpus(0);

    let result = config.build();
    assert!(result.is_err());

    match result {
        Err(CloudHypervisorError::Config(msg)) => {
            assert!(msg.contains("At least one CPU is required"));
        }
        _ => panic!("Expected Config error"),
    }
}

#[test]
fn test_vm_config_build_no_memory() {
    let config = VMConfig::new()
        .with_kernel("/boot/vmlinux")
        .with_cpus(2)
        .with_memory(0);

    let result = config.build();
    assert!(result.is_err());

    match result {
        Err(CloudHypervisorError::Config(msg)) => {
            assert!(msg.contains("Memory size must be greater than 0"));
        }
        _ => panic!("Expected Config error"),
    }
}

#[test]
fn test_cloud_hypervisor_config_builder() {
    let config = CloudHypervisorConfig::new("/usr/bin/cloud-hypervisor")
        .with_api_socket("/tmp/test.sock")
        .with_log_file("/tmp/ch.log")
        .with_seccomp(false)
        .with_landlock(false);

    assert_eq!(
        config.binary_path,
        PathBuf::from("/usr/bin/cloud-hypervisor")
    );
    assert_eq!(config.api_socket_path, PathBuf::from("/tmp/test.sock"));
    assert_eq!(config.log_file, Some(PathBuf::from("/tmp/ch.log")));
    assert!(!config.seccomp);
    assert!(!config.landlock);
}

#[test]
fn test_cpu_config_default() {
    let cpu_config = CpuConfig::default();
    assert_eq!(cpu_config.boot_vcpus, 1);
    assert_eq!(cpu_config.max_vcpus, 1);
}

#[test]
fn test_memory_config_default() {
    let mem_config = MemoryConfig::default();
    assert_eq!(mem_config.size, 512 * 1024 * 1024);
    assert!(!mem_config.mergeable);
    assert!(!mem_config.shared);
    assert!(!mem_config.hugepages);
}

#[test]
fn test_rng_config_default() {
    let rng_config = RngConfig::default();
    assert!(matches!(rng_config.src, RngSource::Urandom));
}

#[test]
fn test_vm_config_chaining() {
    let mut config = VMConfig::new()
        .with_kernel("/boot/vmlinux")
        .with_initramfs("/boot/initrd")
        .with_cpus(8)
        .with_memory(4096);

    config
        .add_virtio_blk("/disk1.img", false)
        .add_virtio_blk("/disk2.img", true)
        .add_virtio_net("tap0")
        .add_vhost_user_net("/tmp/vhost-net.sock");

    assert_eq!(config.disks.len(), 2);
    assert!(!config.disks[0].readonly);
    assert!(config.disks[1].readonly);
    assert_eq!(config.net.len(), 1);
    assert_eq!(config.vhost_user_net.len(), 1);
}

#[test]
fn test_disk_config_properties() {
    let disk = DiskConfig {
        path: PathBuf::from("/test.img"),
        readonly: true,
        direct: false,
        vhost_user: false,
        socket: None,
    };

    assert_eq!(disk.path, PathBuf::from("/test.img"));
    assert!(disk.readonly);
    assert!(!disk.direct);
}

#[test]
fn test_net_config_properties() {
    let net = NetConfig {
        tap: Some("tap0".to_string()),
        mac: Some("00:11:22:33:44:55".to_string()),
        vhost_user: false,
        socket: None,
    };

    assert_eq!(net.tap, Some("tap0".to_string()));
    assert_eq!(net.mac, Some("00:11:22:33:44:55".to_string()));
    assert!(!net.vhost_user);
}

#[test]
fn test_vfio_config() {
    let mut config = VMConfig::new()
        .with_kernel("/boot/vmlinux")
        .with_cpus(2)
        .with_memory(1024);

    config.add_vfio("0000:00:02.0");

    assert_eq!(config.vfio.len(), 1);
    assert_eq!(config.vfio[0].device, "0000:00:02.0");
}

#[test]
fn test_fs_config() {
    let mut config = VMConfig::new()
        .with_kernel("/boot/vmlinux")
        .with_cpus(2)
        .with_memory(1024);

    config.add_virtio_fs("myfs", "/shared");

    assert_eq!(config.fs.len(), 1);
    assert_eq!(config.fs[0].tag, "myfs");
}
