use super::error::BtrfsError;
use super::cmd::{subvolume_create_execute, subvolume_delete_execute, subvolume_show_execute_and_parse};
use super::path_utils::{ensure_btrfs, path_to_str};
use super::types::SubvolumeInfo;
use std::path::{Path, PathBuf};

#[derive(Clone)]
pub struct SubvolumeManager {
    subvolume_path: PathBuf,
    subvolume_path_str: String,
}

impl SubvolumeManager {
    /// Create a new SubvolumeManager for a given subvolume path.
    ///
    /// # Returns
    ///
    /// Returns a `SubvolumeManager` instance if the parent is on Btrfs, or an error otherwise.
    ///
    /// # Example
    ///
    /// ```rust,no_run
    /// use herolib_os::virt::btrfs::SubvolumeManager;
    /// let manager = SubvolumeManager::new("/mnt/btrfs/subvol")?;
    /// ```
    pub fn new(subvolume_path: &Path) -> Result<Self, BtrfsError> {
        let subvolume_path_str = path_to_str(subvolume_path)?.to_string();
        Ok(Self {
            subvolume_path: subvolume_path.to_path_buf(),
            subvolume_path_str,
        })
    }

    /// Create a new subvolume at the specified path
    ///
    /// Returns the subvolume information after creation.
    ///
    /// # Example
    ///
    /// ```rust,no_run
    /// let info = SubvolumeManager::create("/mnt/btrfs/new_subvol")?;
    /// println!("Created subvolume with ID: {}", info.id);
    /// ```
    pub fn create(subvolume_path: &Path) -> Result<SubvolumeInfo, BtrfsError> {
        ensure_parent_is_btrfs(subvolume_path)?;

        let subvolume_path_str = path_to_str(subvolume_path)?;

        // Check if subvolume already exists
        if let Ok(_) = subvolume_show_execute_and_parse(subvolume_path_str) {
            return Err(BtrfsError::CommandFailed(format!(
                "Subvolume already exists at {}",
                subvolume_path_str
            )));
        }

        // Create the subvolume
        subvolume_create_execute(subvolume_path_str)
            .map_err(|e| BtrfsError::CommandFailed(format!(
                "Failed to create subvolume at {}: {}",
                subvolume_path_str, e
            )))?;

        // Get info for the newly created subvolume
        let manager = Self {
            subvolume_path: subvolume_path.to_path_buf(),
            subvolume_path_str: subvolume_path_str.to_string(),
        };
        manager.info()
    }

    /// Delete the subvolume
    ///
    /// # Example
    ///
    /// ```rust,no_run
    /// manager.delete()?;
    /// ```
    pub fn delete(&self) -> Result<(), BtrfsError> {
        subvolume_delete_execute(&self.subvolume_path_str)
            .map_err(|e| BtrfsError::CommandFailed(format!(
                "Failed to delete subvolume at {}: {}",
                self.subvolume_path_str, e
            )))?;

        Ok(())
    }

    /// Get information about the subvolume
    ///
    /// # Example
    ///
    /// ```rust,no_run
    /// let info = manager.info()?;
    /// println!("Subvolume ID: {}", info.id);
    /// println!("Generation: {}", info.generation);
    /// ```
    pub fn info(&self) -> Result<SubvolumeInfo, BtrfsError> {
        subvolume_show_execute_and_parse(&self.subvolume_path_str)
            .map_err(|e| BtrfsError::CommandFailed(format!(
                "Failed to get subvolume info for {}: {}",
                self.subvolume_path_str, e
            )))
    }

    /// Get the subvolume path
    pub fn subvolume_path(&self) -> &Path {
        &self.subvolume_path
    }

    /// Get the subvolume path as string
    pub fn subvolume_path_str(&self) -> &str {
        &self.subvolume_path_str
    }
}

fn ensure_parent_is_btrfs(subvolume_path: &Path) -> Result<(), BtrfsError> {
    if let Some(parent) = subvolume_path.parent() {
        ensure_btrfs(parent)?;
    } else {
        return Err(BtrfsError::CommandFailed(format!(
            "Subvolume path {} has no parent directory",
            path_to_str(subvolume_path).unwrap_or("<invalid path>")
        )));
    }
    Ok(())
}

