//! DBus interface implementation for apt-ostree daemon

use zbus::{fdo, interface};
use crate::daemon::{
    DaemonConfig, DaemonResult, DaemonError,
    TransactionManager, TransactionType,
    OstreeManager, AptManager, SecurityManager, SysrootManager, OsManager,
};
use std::sync::Arc;
use tokio::sync::RwLock;
use std::collections::HashMap;


/// DBus interface for apt-ostree daemon
#[allow(dead_code, clippy::new_without_default)]
pub struct DaemonDBus {
    config: DaemonConfig,
    transaction_manager: Arc<RwLock<TransactionManager>>,
    ostree_manager: Arc<RwLock<OstreeManager>>,
    apt_manager: Arc<RwLock<AptManager>>,
    security_manager: Arc<RwLock<SecurityManager>>,
    sysroot_manager: Arc<RwLock<SysrootManager>>,
    os_manager: Arc<RwLock<OsManager>>,
}

impl DaemonDBus {
    pub fn new(config: DaemonConfig) -> DaemonResult<Self> {
        let transaction_manager = Arc::new(RwLock::new(TransactionManager::new()));
        let ostree_manager = Arc::new(RwLock::new(OstreeManager::new(&config.ostree_sysroot)?));
        let apt_manager = Arc::new(RwLock::new(AptManager::new(&config.apt_cache_dir)?));
        let security_manager = Arc::new(RwLock::new(SecurityManager::new()));
        let sysroot_manager = Arc::new(RwLock::new(SysrootManager::new(&config.ostree_sysroot)?));
        let os_manager = Arc::new(RwLock::new(OsManager::new()?));

        Ok(Self {
            config,
            transaction_manager,
            ostree_manager,
            apt_manager,
            security_manager,
            sysroot_manager,
            os_manager,
        })
    }
}



#[interface(name = "org.projectatomic.aptostree1")]
impl DaemonDBus {
    /// Get daemon version
    async fn get_version(&self) -> fdo::Result<String> {
        Ok(env!("CARGO_PKG_VERSION").to_string())
    }

    /// Get daemon status
    async fn get_status(&self) -> fdo::Result<String> {
        // Get system status from various managers
        let mut status = HashMap::new();
        
        // Check APT status
        let apt_status = {
            let apt = self.apt_manager.read().await;
            apt.get_cache_status().unwrap_or_else(|_| "unknown".to_string())
        };
        status.insert("apt", apt_status);
        
        // Check OSTree status
        let ostree_status = {
            let ostree = self.ostree_manager.read().await;
            ostree.get_system_status().unwrap_or_else(|_| "unknown".to_string())
        };
        status.insert("ostree", ostree_status);
        
        // Check transaction status
        let transaction_count = {
            let tm = self.transaction_manager.read().await;
            tm.get_active_transaction_count()
        };
        status.insert("active_transactions", transaction_count.to_string());
        
        // Convert to JSON
        serde_json::to_string(&status)
            .map_err(|e| fdo::Error::Failed(format!("Failed to serialize status: {}", e)))
    }

    /// Start a new transaction
    async fn start_transaction(&self, transaction_type: String) -> fdo::Result<String> {
        let transaction_id = {
            let mut tm = self.transaction_manager.write().await;
            tm.start_transaction(TransactionType::from_str(&transaction_type)
                .map_err(|e| fdo::Error::Failed(format!("Invalid transaction type: {}", e)))?)
        };
        Ok(transaction_id)
    }

    /// Get transaction status
    async fn get_transaction_status(&self, transaction_id: String) -> fdo::Result<String> {
        let status = {
            let tm = self.transaction_manager.read().await;
            tm.get_transaction_status(&transaction_id)
                .map_err(|e| fdo::Error::Failed(format!("Transaction error: {}", e)))?
        };
        Ok(status.to_string())
    }

    /// Install packages
    async fn install_packages(&self, transaction_id: String, packages: Vec<String>) -> fdo::Result<bool> {
        tracing::info!("Installing packages: {:?}", packages);
        
        // Start transaction
        let mut tm = self.transaction_manager.write().await;
        tm.start_existing_transaction(&transaction_id)
            .map_err(|e| fdo::Error::Failed(format!("Failed to start transaction: {}", e)))?;
        
        // Install packages
        {
            let apt = self.apt_manager.read().await;
            apt.install_packages(&packages)
                .map_err(|e| fdo::Error::Failed(format!("Package installation failed: {}", e)))?;
        }
        
        // Complete transaction
        tm.complete_transaction(&transaction_id, true, "Packages installed successfully".to_string())
            .map_err(|e| fdo::Error::Failed(format!("Failed to complete transaction: {}", e)))?;
        
        tracing::info!("Packages installed successfully");
        Ok(true)
    }

    /// Remove packages
    async fn remove_packages(&self, transaction_id: String, packages: Vec<String>) -> fdo::Result<bool> {
        tracing::info!("Removing packages: {:?}", packages);
        
        // Start transaction
        let mut tm = self.transaction_manager.write().await;
        tm.start_existing_transaction(&transaction_id)
            .map_err(|e| fdo::Error::Failed(format!("Failed to start transaction: {}", e)))?;
        
        // Remove packages
        {
            let apt = self.apt_manager.read().await;
            apt.remove_packages(&packages)
                .map_err(|e| fdo::Error::Failed(format!("Package removal failed: {}", e)))?;
        }
        
        // Complete transaction
        tm.complete_transaction(&transaction_id, true, "Packages removed successfully".to_string())
            .map_err(|e| fdo::Error::Failed(format!("Failed to complete transaction: {}", e)))?;
        
        tracing::info!("Packages removed successfully");
        Ok(true)
    }

    /// Upgrade system
    async fn upgrade(&self, transaction_id: String) -> fdo::Result<bool> {
        tracing::info!("Upgrading system");
        
        // Start transaction
        let mut tm = self.transaction_manager.write().await;
        tm.start_existing_transaction(&transaction_id)
            .map_err(|e| fdo::Error::Failed(format!("Failed to start transaction: {}", e)))?;
        
        // Upgrade system
        {
            let apt = self.apt_manager.read().await;
            apt.upgrade_system()
                .map_err(|e| fdo::Error::Failed(format!("System upgrade failed: {}", e)))?;
        }
        
        // Complete transaction
        tm.complete_transaction(&transaction_id, true, "System upgraded successfully".to_string())
            .map_err(|e| fdo::Error::Failed(format!("Failed to complete transaction: {}", e)))?;
        
        tracing::info!("System upgraded successfully");
        Ok(true)
    }

    /// Rollback system
    async fn rollback(&self, transaction_id: String) -> fdo::Result<bool> {
        tracing::info!("Rolling back system");
        
        // Start transaction
        let mut tm = self.transaction_manager.write().await;
        tm.start_existing_transaction(&transaction_id)
            .map_err(|e| fdo::Error::Failed(format!("Failed to start transaction: {}", e)))?;
        
        // Rollback system
        {
            let ostree = self.ostree_manager.read().await;
            ostree.rollback_deployment()
                .map_err(|e| fdo::Error::Failed(format!("System rollback failed: {}", e)))?;
        }
        
        // Complete transaction
        tm.complete_transaction(&transaction_id, true, "System rolled back successfully".to_string())
            .map_err(|e| fdo::Error::Failed(format!("Failed to complete transaction: {}", e)))?;
        
        tracing::info!("System rolled back successfully");
        Ok(true)
    }

    /// Deploy new deployment
    async fn deploy(&self, transaction_id: String, refspec: String) -> fdo::Result<bool> {
        tracing::info!("Deploying refspec: {}", refspec);
        
        // Start transaction
        let mut tm = self.transaction_manager.write().await;
        tm.start_existing_transaction(&transaction_id)
            .map_err(|e| fdo::Error::Failed(format!("Failed to start transaction: {}", e)))?;
        
        // Deploy refspec
        {
            let ostree = self.ostree_manager.read().await;
            ostree.deploy_ref(&refspec)
                .map_err(|e| fdo::Error::Failed(format!("Deployment failed: {}", e)))?;
        }
        
        // Complete transaction
        tm.complete_transaction(&transaction_id, true, format!("Deployed refspec: {}", refspec))
            .map_err(|e| fdo::Error::Failed(format!("Failed to complete transaction: {}", e)))?;
        
        tracing::info!("Deployed refspec: {}", refspec);
        Ok(true)
    }

    /// Rebase system
    async fn rebase(&self, transaction_id: String, refspec: String) -> fdo::Result<bool> {
        tracing::info!("Rebasing to refspec: {}", refspec);
        
        // Start transaction
        let mut tm = self.transaction_manager.write().await;
        tm.start_existing_transaction(&transaction_id)
            .map_err(|e| fdo::Error::Failed(format!("Failed to start transaction: {}", e)))?;
        
        // Rebase to refspec
        {
            let ostree = self.ostree_manager.read().await;
            ostree.rebase_to_ref(&refspec)
                .map_err(|e| fdo::Error::Failed(format!("Rebase failed: {}", e)))?;
        }
        
        // Complete transaction
        tm.complete_transaction(&transaction_id, true, format!("Rebased to refspec: {}", refspec))
            .map_err(|e| fdo::Error::Failed(format!("Failed to complete transaction: {}", e)))?;
        
        tracing::info!("Rebased to refspec: {}", refspec);
        Ok(true)
    }

    /// Reload daemon
    async fn reload(&self) -> fdo::Result<bool> {
        // TODO: Implement real reload
        tracing::info!("Reloading daemon");
        Ok(true)
    }

    /// Shutdown daemon
    async fn shutdown(&self) -> fdo::Result<bool> {
        // TODO: Implement graceful shutdown
        tracing::info!("Shutting down daemon");
        Ok(true)
    }
}

impl TransactionType {
    fn from_str(s: &str) -> Result<Self, DaemonError> {
        match s {
            "install" => Ok(TransactionType::Install),
            "remove" => Ok(TransactionType::Remove),
            "upgrade" => Ok(TransactionType::Upgrade),
            "rollback" => Ok(TransactionType::Rollback),
            "deploy" => Ok(TransactionType::Deploy),
            "rebase" => Ok(TransactionType::Rebase),
            _ => Err(DaemonError::Configuration(format!("Unknown transaction type: {}", s))),
        }
    }
}
