use crate::virt::btrfs::{
    DeviceManager, FilesystemManager, SubvolumeManager, QuotaManager,
    DeviceType,
    SubvolumeInfo, BtrfsSubvolumeEntry, QuotaGroup,
    FilesystemUsageStructured, GroupUsage,
};
use rhai::{Array, Engine, EvalAltResult};
use std::path::Path;

fn to_rhai_error<T>(result: Result<T, crate::virt::btrfs::BtrfsError>) -> Result<T, Box<EvalAltResult>> {
    result.map_err(|e| {
        Box::new(EvalAltResult::ErrorRuntime(
            e.to_string().into(),
            rhai::Position::NONE,
        ))
    })
}

// DeviceManager functions
pub fn device_manager_new(device_path: &str) -> Result<DeviceManager, Box<EvalAltResult>> {
    to_rhai_error(DeviceManager::new(device_path))
}

pub fn device_format(manager: &mut DeviceManager, label: Option<&str>) -> Result<(), Box<EvalAltResult>> {
    to_rhai_error(manager.format(label))
}

pub fn device_format_with_label(manager: &mut DeviceManager, label: &str) -> Result<(), Box<EvalAltResult>> {
    to_rhai_error(manager.format(Some(label)))
}

pub fn device_format_no_label(manager: &mut DeviceManager) -> Result<(), Box<EvalAltResult>> {
    to_rhai_error(manager.format(None))
}

pub fn device_manager_shutdown(manager: &DeviceManager) -> Result<(), Box<EvalAltResult>> {
    to_rhai_error(manager.shutdown())
}

pub fn device_set_type(manager: &DeviceManager, device_type: &str) -> Result<(), Box<EvalAltResult>> {
    let dt = DeviceType::from_str(device_type).ok_or_else(|| {
        Box::new(EvalAltResult::ErrorRuntime(
            format!("Invalid device type: {}. Must be 'SSD' or 'HDD'", device_type).into(),
            rhai::Position::NONE,
        ))
    })?;
    to_rhai_error(manager.set_type(dt))
}

pub fn device_get_type(manager: &DeviceManager) -> Result<String, Box<EvalAltResult>> {
    match to_rhai_error(manager.get_type())? {
        Some(dt) => Ok(dt.as_str().to_string()),
        None => Ok(String::new()),
    }
}


// FilesystemManager functions
pub fn filesystem_manager_new(device_path: &str) -> Result<FilesystemManager, Box<EvalAltResult>> {
    to_rhai_error(FilesystemManager::new(device_path))
}

pub fn filesystem_mount(manager: &mut FilesystemManager, mountpoint: &str) -> Result<(), Box<EvalAltResult>> {
    to_rhai_error(manager.mount(mountpoint))
}

pub fn filesystem_unmount(manager: &mut FilesystemManager) -> Result<(), Box<EvalAltResult>> {
    to_rhai_error(manager.unmount())
}

pub fn filesystem_usage(manager: FilesystemManager) -> Result<FilesystemUsageStructured, Box<EvalAltResult>> {
    to_rhai_error(manager.usage())
}

pub fn filesystem_list_subvolumes(manager: FilesystemManager) -> Result<Array, Box<EvalAltResult>> {
    let subvolumes = to_rhai_error(manager.list_subvolumes())?;
    Ok(subvolumes.into_iter().map(rhai::Dynamic::from).collect())
}

// SubvolumeManager functions
pub fn subvolume_manager_new(path: &str) -> Result<SubvolumeManager, Box<EvalAltResult>> {
    to_rhai_error(SubvolumeManager::new(Path::new(path)))
}

pub fn subvolume_create(path: &str) -> Result<SubvolumeInfo, Box<EvalAltResult>> {
    to_rhai_error(SubvolumeManager::create(Path::new(path)))
}

pub fn subvolume_delete(manager: SubvolumeManager) -> Result<(), Box<EvalAltResult>> {
    to_rhai_error(manager.delete())
}

pub fn subvolume_info(manager: SubvolumeManager) -> Result<SubvolumeInfo, Box<EvalAltResult>> {
    to_rhai_error(manager.info())
}


// QuotaManager functions
pub fn quota_manager_new(filesystem_path: &str) -> Result<QuotaManager, Box<EvalAltResult>> {
    to_rhai_error(QuotaManager::new(Path::new(filesystem_path)))
}

pub fn quota_is_enabled(manager: QuotaManager) -> Result<bool, Box<EvalAltResult>> {
    to_rhai_error(manager.is_enabled())
}

pub fn quota_enable(manager: QuotaManager) -> Result<(), Box<EvalAltResult>> {
    to_rhai_error(manager.enable())
}

pub fn quota_list(manager: QuotaManager) -> Result<Array, Box<EvalAltResult>> {
    let qgroups = to_rhai_error(manager.list())?;
    Ok(qgroups.into_iter().map(rhai::Dynamic::from).collect())
}

pub fn quota_set_subvolume_limit(manager: QuotaManager, path: &str, limit: i64) -> Result<(), Box<EvalAltResult>> {
    if limit < 0 {
        return Err(Box::new(EvalAltResult::ErrorRuntime(
            "Limit must be non-negative".into(),
            rhai::Position::NONE,
        )));
    }
    to_rhai_error(manager.set_subvolume_limit(Path::new(path), limit as u64))
}

pub fn quota_get_subvolume_usage(manager: QuotaManager, path: &str) -> Result<i64, Box<EvalAltResult>> {
    let usage = to_rhai_error(manager.get_subvolume_usage(Path::new(path)))?;
    Ok(usage as i64)
}

pub fn quota_destroy_qgroup(manager: QuotaManager, qgroup: &str) -> Result<(), Box<EvalAltResult>> {
    to_rhai_error(manager.destroy_qgroup(qgroup))
}


pub fn register_btrfs_module(engine: &mut Engine) -> Result<(), Box<EvalAltResult>> {
    // Register types
    engine.register_type::<DeviceManager>();
    engine.register_type::<FilesystemManager>();
    engine.register_type::<SubvolumeManager>();
    engine.register_type::<QuotaManager>();
    engine.register_type::<SubvolumeInfo>();
    engine.register_type::<BtrfsSubvolumeEntry>();
    engine.register_type::<QuotaGroup>();
    engine.register_type::<FilesystemUsageStructured>();
    engine.register_type::<GroupUsage>();

    // Register minimal getters for fields used in scripts
    engine.register_get("id", |info: &mut SubvolumeInfo| info.id as i64);
    engine.register_get("name", |info: &mut SubvolumeInfo| info.name.clone());
    engine.register_get("path", |info: &mut SubvolumeInfo| info.path.to_string_lossy().to_string());
    
    engine.register_get("id", |entry: &mut BtrfsSubvolumeEntry| entry.id as i64);
    engine.register_get("path", |entry: &mut BtrfsSubvolumeEntry| entry.path.clone());
    
    engine.register_get("qgroupid", |qg: &mut QuotaGroup| qg.qgroupid.clone());
    engine.register_get("referenced", |qg: &mut QuotaGroup| qg.referenced as i64);
    engine.register_get("exclusive", |qg: &mut QuotaGroup| qg.exclusive as i64);
    engine.register_get("max_referenced", |qg: &mut QuotaGroup| qg.max_referenced.map(|v| v as i64).unwrap_or(-1));
    engine.register_get("max_exclusive", |qg: &mut QuotaGroup| qg.max_exclusive.map(|v| v as i64).unwrap_or(-1));
    
    engine.register_get("total", |gu: &mut GroupUsage| gu.total as i64);
    engine.register_get("used", |gu: &mut GroupUsage| gu.used as i64);
    engine.register_get("profile", |gu: &mut GroupUsage| gu.profile.clone());
    
    engine.register_get("data", |fs: &mut FilesystemUsageStructured| fs.data.clone());
    engine.register_get("metadata", |fs: &mut FilesystemUsageStructured| fs.metadata.clone());
    engine.register_get("system", |fs: &mut FilesystemUsageStructured| fs.system.clone());
    engine.register_get("globalreserved", |fs: &mut FilesystemUsageStructured| fs.globalreserved.clone());

    // Register DeviceManager functions
    engine.register_fn("device_manager_new", device_manager_new);
    engine.register_fn("device_format", device_format_with_label);
    engine.register_fn("device_format", device_format_no_label);
    engine.register_fn("device_shutdown", device_manager_shutdown);
    engine.register_fn("device_set_type", device_set_type);
    engine.register_fn("device_get_type", device_get_type);

    // Register FilesystemManager functions
    engine.register_fn("filesystem_manager_new", filesystem_manager_new);
    engine.register_fn("filesystem_mount", filesystem_mount);
    engine.register_fn("filesystem_unmount", filesystem_unmount);
    engine.register_fn("filesystem_usage", filesystem_usage);
    engine.register_fn("filesystem_list_subvolumes", filesystem_list_subvolumes);

    // Register SubvolumeManager functions
    engine.register_fn("subvolume_manager_new", subvolume_manager_new);
    engine.register_fn("subvolume_create", subvolume_create);
    engine.register_fn("subvolume_delete", subvolume_delete);
    engine.register_fn("subvolume_info", subvolume_info);


    // Register QuotaManager functions
    engine.register_fn("quota_manager_new", quota_manager_new);
    engine.register_fn("quota_is_enabled", quota_is_enabled);
    engine.register_fn("quota_enable", quota_enable);
    engine.register_fn("quota_list", quota_list);
    engine.register_fn("quota_set_subvolume_limit", quota_set_subvolume_limit);
    engine.register_fn("quota_get_subvolume_usage", quota_get_subvolume_usage);
    engine.register_fn("quota_destroy_qgroup", quota_destroy_qgroup);


    Ok(())
}
