use super::error::BtrfsError;
use super::cmd::{qgroup_destroy_execute, qgroup_limit_execute, qgroup_show_execute, qgroup_show_execute_and_parse, quota_enable_execute};
use super::subvolume::SubvolumeManager;
use super::path_utils::path_to_str;
use super::types::QuotaGroup;
use std::path::{Path, PathBuf};

const QGROUP_ROOT_PREFIX: &str = "0/";

#[derive(Clone)]
pub struct QuotaManager {
    filesystem_path: PathBuf,
    filesystem_path_str: String,
}

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

    /// Check if quota is enabled for the filesystem
    ///
    /// # Returns
    ///
    /// Returns `true` if quota is enabled, `false` otherwise.
    ///
    /// # Example
    ///
    /// ```rust,no_run
    /// if manager.is_enabled()? {
    ///     println!("Quota is enabled");
    /// } else {
    ///     println!("Quota is not enabled");
    /// }
    /// ```
    pub fn is_enabled(&self) -> Result<bool, BtrfsError> {
        match qgroup_show_execute(&self.filesystem_path_str, false, false) {
            Ok(_) => Ok(true),
            Err(BtrfsError::CommandFailed(_)) => Ok(false),
            Err(e) => Err(BtrfsError::QuotaError(format!("Failed to check quota status for {}: {}", self.filesystem_path_str, e))),
        }
    }

    /// Enable quota for the filesystem
    ///
    /// If quota is already enabled, this method returns successfully without doing anything.
    ///
    /// # Example
    ///
    /// ```rust,no_run
    /// manager.enable()?;
    /// ```
    pub fn enable(&self) -> Result<(), BtrfsError> {
        if self.is_enabled()? {
            return Ok(());
        }
        
        quota_enable_execute(&self.filesystem_path_str)
            .map_err(|e| BtrfsError::QuotaError(format!("Failed to enable quota for {}: {}", self.filesystem_path_str, e)))?;
        
        Ok(())
    }

    /// List all quota groups in the filesystem
    ///
    /// # Returns
    ///
    /// Returns a vector of `QuotaGroup` entries representing all quota groups.
    ///
    /// # Example
    ///
    /// ```rust,no_run
    /// let qgroups = manager.list()?;
    /// for qg in qgroups {
    ///     println!("Qgroup: {}, Referenced: {}", qg.qgroupid, qg.referenced);
    /// }
    /// ```
    pub fn list(&self) -> Result<Vec<QuotaGroup>, BtrfsError> {
        if !self.is_enabled()? {
            return Err(BtrfsError::QuotaNotEnabled(format!("Quota is not enabled for {}", self.filesystem_path_str)));
        }

        let entries = qgroup_show_execute_and_parse(&self.filesystem_path_str, true)
            .map_err(|e| BtrfsError::QuotaError(format!("Failed to list qgroups for {}: {}", self.filesystem_path_str, e)))?;

        Ok(entries.into_iter().map(|entry| {
            let max_referenced = entry.max_referenced_parsed();
            let max_exclusive = entry.max_exclusive_parsed();
            QuotaGroup {
                qgroupid: entry.qgroupid,
                referenced: entry.referenced,
                max_referenced,
                exclusive: entry.exclusive,
                max_exclusive,
                path: entry.path,
                parents: entry.parents,
                children: entry.children,
            }
        }).collect())
    }

    /// Destroy a quota group
    ///
    /// # Arguments
    ///
    /// * `qgroup` - The quota group ID in the format `level/id` (e.g., `0/256`)
    ///
    /// # Example
    ///
    /// ```rust,no_run
    /// manager.destroy_qgroup("0/256")?;
    /// ```
    pub fn destroy_qgroup(&self, qgroup: &str) -> Result<(), BtrfsError> {
        if !qgroup.contains('/') {
            return Err(BtrfsError::QuotaError(format!(
                "Invalid qgroup ID format: {}. Expected format: level/id (e.g., 0/256)",
                qgroup
            )));
        }
        
        qgroup_destroy_execute(qgroup, &self.filesystem_path_str)
            .map_err(|e| BtrfsError::QuotaError(format!("Failed to destroy qgroup {}: {}", qgroup, e)))?;
        
        Ok(())
    }

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

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

    /// Set a quota limit for a subvolume
    ///
    /// # Arguments
    ///
    /// * `subvolume_path` - Path to the subvolume
    /// * `limit` - The quota limit in bytes
    ///
    /// # Example
    ///
    /// ```rust,no_run
    /// // Set a 10GB limit for a subvolume
    /// manager.set_subvolume_limit("/mnt/btrfs/subvol", 10_737_418_240)?;
    /// ```
    pub fn set_subvolume_limit(&self, subvolume_path: &Path, limit: u64) -> Result<(), BtrfsError> {
        if !self.is_enabled()? {
            return Err(BtrfsError::QuotaNotEnabled(format!("Quota is not enabled for {}", self.filesystem_path_str)));
        }

        let subvolume = SubvolumeManager::new(subvolume_path)?;
        let info = subvolume.info()?;
        
        let qgroup_id = format!("{}{}", QGROUP_ROOT_PREFIX, info.id);
        let subvolume_path_str = path_to_str(subvolume_path)?;
        
        qgroup_limit_execute(limit, &qgroup_id, &self.filesystem_path_str)
            .map_err(|e| BtrfsError::QuotaError(format!("Failed to set limit {} for subvolume {} (qgroup {}): {}", limit, subvolume_path_str, qgroup_id, e)))?;
        
        Ok(())
    }

    /// Get the current usage for a subvolume
    ///
    /// # Arguments
    ///
    /// * `subvolume_path` - Path to the subvolume
    ///
    /// # Returns
    ///
    /// Returns the referenced bytes used by the subvolume.
    ///
    /// # Example
    ///
    /// ```rust,no_run
    /// let usage = manager.get_subvolume_usage("/mnt/btrfs/subvol")?;
    /// println!("Subvolume is using {} bytes", usage);
    /// ```
    pub fn get_subvolume_usage(&self, subvolume_path: &Path) -> Result<u64, BtrfsError> {
        if !self.is_enabled()? {
            return Err(BtrfsError::QuotaNotEnabled(format!("Quota is not enabled for {}", self.filesystem_path_str)));
        }

        let subvolume = SubvolumeManager::new(subvolume_path)?;
        let info = subvolume.info()?;
        
        let qgroup_id = format!("{}{}", QGROUP_ROOT_PREFIX, info.id);
        let subvolume_path_str = path_to_str(subvolume_path)?;
        let qgroups = self.list()?;
        
        let qgroup = qgroups
            .iter()
            .find(|qg| qg.qgroupid == qgroup_id)
            .ok_or_else(|| BtrfsError::QuotaError(format!("Quota group {} not found for subvolume {}", qgroup_id, subvolume_path_str)))?;
        
        Ok(qgroup.referenced)
    }
}
