//! Package manager integration for apt-ostree compose

use std::path::PathBuf;
use std::process::Command;
use apt_ostree::lib::error::{AptOstreeError, AptOstreeResult};
use super::treefile::Repository;

/// Package manager for APT operations
pub struct PackageManager {
    build_root: PathBuf,
    apt_config_dir: PathBuf,
    sources_list_path: PathBuf,
    preferences_path: PathBuf,
}

impl PackageManager {
    /// Create a new package manager instance
    pub fn new(_options: &crate::commands::compose::ComposeOptions) -> AptOstreeResult<Self> {
        let build_root = PathBuf::from("/tmp/apt-ostree-build");
        let apt_config_dir = build_root.join("etc/apt");
        let sources_list_path = apt_config_dir.join("sources.list");
        let preferences_path = apt_config_dir.join("preferences");
        
        Ok(Self {
            build_root,
            apt_config_dir,
            sources_list_path,
            preferences_path,
        })
    }
    
    /// Set up package sources from treefile repositories
    pub async fn setup_package_sources(&self, repositories: &[Repository]) -> AptOstreeResult<()> {
        println!("Setting up package sources...");
        
        // Ensure APT config directory exists
        std::fs::create_dir_all(&self.apt_config_dir)
            .map_err(|e| AptOstreeError::System(format!("Failed to create APT config directory: {}", e)))?;
        
        // Write sources.list
        let mut sources_content = String::new();
        for repo in repositories {
            sources_content.push_str(&format!("{}\n", repo.url));
        }
        
        std::fs::write(&self.sources_list_path, sources_content)
            .map_err(|e| AptOstreeError::System(format!("Failed to write sources.list: {}", e)))?;
        
        // Create preferences file for package pinning if needed
        let preferences_content = "# Package preferences for apt-ostree compose\n";
        std::fs::write(&self.preferences_path, preferences_content)
            .map_err(|e| AptOstreeError::System(format!("Failed to write preferences: {}", e)))?;
        
        println!("✅ Package sources configured successfully");
        Ok(())
    }
    
    /// Update package cache
    pub async fn update_cache(&self) -> AptOstreeResult<()> {
        println!("Updating package cache...");
        
        // Use chroot to run apt-get update in the build environment
        let output = Command::new("chroot")
            .arg(&self.build_root)
            .arg("apt-get")
            .arg("update")
            .output()
            .map_err(|e| AptOstreeError::System(format!("Failed to run apt-get update: {}", e)))?;
        
        if !output.status.success() {
            let stderr = String::from_utf8_lossy(&output.stderr);
            return Err(AptOstreeError::System(format!("apt-get update failed: {}", stderr)));
        }
        
        println!("✅ Package cache updated successfully");
        Ok(())
    }
    
    /// Install a package using APT
    pub async fn install_package(&self, package: &str) -> AptOstreeResult<()> {
        println!("Installing package: {}", package);
        
        // Use chroot to run apt-get install in the build environment
        let output = Command::new("chroot")
            .arg(&self.build_root)
            .arg("apt-get")
            .arg("install")
            .arg("-y") // Non-interactive
            .arg("--no-install-recommends") // Don't install recommended packages
            .arg(package)
            .output()
            .map_err(|e| AptOstreeError::System(format!("Failed to run apt-get install: {}", e)))?;
        
        if !output.status.success() {
            let stderr = String::from_utf8_lossy(&output.stderr);
            return Err(AptOstreeError::System(format!("apt-get install {} failed: {}", package, stderr)));
        }
        
        println!("✅ Package {} installed successfully", package);
        Ok(())
    }
    
    /// Resolve package dependencies
    pub async fn resolve_dependencies(&self, packages: &[String]) -> AptOstreeResult<Vec<String>> {
        println!("Resolving package dependencies...");
        
        let mut all_packages = Vec::new();
        
        for package in packages {
            // Use apt-cache to get dependencies
            let output = Command::new("chroot")
                .arg(&self.build_root)
                .arg("apt-cache")
                .arg("depends")
                .arg(package)
                .output()
                .map_err(|e| AptOstreeError::System(format!("Failed to get dependencies for {}: {}", package, e)))?;
            
            if output.status.success() {
                let stdout = String::from_utf8_lossy(&output.stdout);
                for line in stdout.lines() {
                    if line.starts_with("  ") && !line.contains("PreDepends:") {
                        let dep = line.trim();
                        if !all_packages.contains(&dep.to_string()) {
                            all_packages.push(dep.to_string());
                        }
                    }
                }
            }
        }
        
        // Add original packages
        for package in packages {
            if !all_packages.contains(package) {
                all_packages.push(package.clone());
            }
        }
        
        println!("✅ Resolved {} packages (including dependencies)", all_packages.len());
        Ok(all_packages)
    }
    
    /// Run post-installation scripts
    pub async fn run_post_install_scripts(&self) -> AptOstreeResult<()> {
        println!("Running post-installation scripts...");
        
        // Run dpkg configure -a to configure all packages
        let output = Command::new("chroot")
            .arg(&self.build_root)
            .arg("dpkg")
            .arg("--configure")
            .arg("-a")
            .output()
            .map_err(|e| AptOstreeError::System(format!("Failed to run dpkg configure: {}", e)))?;
        
        if !output.status.success() {
            let stderr = String::from_utf8_lossy(&output.stderr);
            println!("Warning: dpkg configure had issues: {}", stderr);
        }
        
        println!("✅ Post-installation scripts completed");
        Ok(())
    }
    
    /// Update package database
    pub async fn update_package_database(&self) -> AptOstreeResult<()> {
        println!("Updating package database...");
        
        // Update package lists
        self.update_cache().await?;
        
        // Clean up any broken packages
        let output = Command::new("chroot")
            .arg(&self.build_root)
            .arg("apt-get")
            .arg("check")
            .output()
            .map_err(|e| AptOstreeError::System(format!("Failed to run apt-get check: {}", e)))?;
        
        if !output.status.success() {
            let stderr = String::from_utf8_lossy(&output.stderr);
            println!("Warning: apt-get check had issues: {}", stderr);
        }
        
        println!("✅ Package database updated successfully");
        Ok(())
    }
    
    /// Initialize base system using debootstrap
    pub async fn initialize_base_system(&self, base_image: &str) -> AptOstreeResult<()> {
        println!("Initializing base system using debootstrap...");
        
        // Extract Debian release from base image (e.g., "debian:trixie" -> "trixie")
        let release = if base_image.contains(':') {
            base_image.split(':').nth(1).unwrap_or("trixie")
        } else {
            base_image
        };
        
        // Use debootstrap to create base system
        let output = Command::new("debootstrap")
            .arg("--variant=minbase")
            .arg("--include=apt,dpkg")
            .arg(release)
            .arg(&self.build_root)
            .arg("http://deb.debian.org/debian")
            .output()
            .map_err(|e| AptOstreeError::System(format!("Failed to run debootstrap: {}", e)))?;
        
        if !output.status.success() {
            let stderr = String::from_utf8_lossy(&output.stderr);
            return Err(AptOstreeError::System(format!("debootstrap failed: {}", stderr)));
        }
        
        println!("✅ Base system initialized successfully");
        Ok(())
    }
    
    /// Clean up package manager state
    pub async fn cleanup(&self) -> AptOstreeResult<()> {
        println!("Cleaning up package manager state...");
        
        // Remove APT cache to reduce image size
        let cache_dir = self.build_root.join("var/cache/apt");
        if cache_dir.exists() {
            std::fs::remove_dir_all(&cache_dir)
                .map_err(|e| AptOstreeError::System(format!("Failed to remove APT cache: {}", e)))?;
        }
        
        // Remove APT lists
        let lists_dir = self.build_root.join("var/lib/apt/lists");
        if lists_dir.exists() {
            std::fs::remove_dir_all(&lists_dir)
                .map_err(|e| AptOstreeError::System(format!("Failed to remove APT lists: {}", e)))?;
        }
        
        println!("✅ Package manager cleanup completed");
        Ok(())
    }
}
