//! Package management commands for apt-ostree

use crate::commands::Command;
use apt_ostree::lib::error::{AptOstreeError, AptOstreeResult};
use apt_ostree::lib::ostree::OstreeManager;
use apt_ostree::lib::apt::AptManager;
use crate::cli::{InstallArgs, UninstallArgs, SearchArgs};

/// Install command - Overlay additional packages
pub struct InstallCommand;

impl InstallCommand {
    pub fn new() -> Self {
        Self
    }
    
    /// Parse install arguments from string array (private method)
    fn parse_install_args(&self, args: &[String]) -> AptOstreeResult<InstallArgs> {
        // This is a simplified parser for the string arguments
        // In a real implementation, this would use the structured CLI args directly
        let mut packages = Vec::new();
        let mut dry_run = false;
        let mut cache_only = false;
        let mut download_only = false;
        let mut apply_live = false;
        let mut reboot = false;
        let mut lock_finalization = false;
        let mut idempotent = false;
        
        for arg in args {
            match arg.as_str() {
                "--dry-run" | "-d" => dry_run = true,
                "--cache-only" | "-c" => cache_only = true,
                "--download-only" => download_only = true,
                "--apply-live" => apply_live = true,
                "--reboot" | "-r" => reboot = true,
                "--lock-finalization" => lock_finalization = true,
                "--idempotent" => idempotent = true,
                "--help" | "-h" => {
                    self.show_help();
                    return Err(AptOstreeError::InvalidArgument("Help requested".to_string()));
                }
                arg if !arg.starts_with('-') => {
                    packages.push(arg.to_string());
                }
                _ => {}
            }
        }
        
        if packages.is_empty() {
            return Err(AptOstreeError::InvalidArgument(
                "No packages specified. Use --help for usage information.".to_string()
            ));
        }
        
        Ok(InstallArgs {
            packages,
            uninstall: None,
            cache_only,
            download_only,
            apply_live,
            force_replacefiles: false,
            stateroot: None,
            reboot,
            dry_run,
            assumeyes: false,
            allow_inactive: false,
            idempotent,
            unchanged_exit_77: false,
            lock_finalization,
            enablerepo: None,
            disablerepo: None,
            releasever: None,
            sysroot: None,
            peer: false,
        })
    }
}

impl Command for InstallCommand {
    fn execute(&self, args: &[String]) -> AptOstreeResult<()> {
        // Parse the structured arguments from the CLI
        let install_args = self.parse_install_args(args)?;
        
        println!("📦 Install Packages");
        println!("===================");
        println!("Packages to install: {}", install_args.packages.join(", "));
        
        if install_args.dry_run {
            println!("Mode: Dry run (no actual installation)");
        }
        if install_args.cache_only {
            println!("Mode: Cache only (no download)");
        }
        if install_args.download_only {
            println!("Mode: Download only (no deployment)");
        }
        if install_args.apply_live {
            println!("Mode: Apply live changes");
        }
        if install_args.reboot {
            println!("Mode: Reboot after operation");
        }
        if install_args.lock_finalization {
            println!("Mode: Lock finalization");
        }
        println!();
        
        // Check if we're on an OSTree system
        let ostree_manager = OstreeManager::new();
        let is_ostree_system = ostree_manager.is_available() && ostree_manager.is_ostree_booted();
        
        if is_ostree_system {
            println!("OSTree: System is booted from OSTree");
            println!("Mode: Package overlay installation");
        } else {
            println!("OSTree: Traditional package management system");
            println!("Mode: Standard package installation");
        }
        println!();
        
        // Use the real APT manager for installation
        let apt_manager = AptManager::new();
        
        // Check if APT is available
        if !apt_manager.check_database_health()? {
            return Err(AptOstreeError::System("APT database is not healthy".to_string()));
        }
        
        if install_args.dry_run {
            println!("🔍 DRY RUN MODE - No packages will be installed");
            println!("Dry run mode - would install the following packages:");
            for package in &install_args.packages {
                if let Ok(Some(pkg_info)) = apt_manager.get_package_info(package) {
                    println!("  {} (version: {})", pkg_info.name, pkg_info.version);
                    println!("    Description: {}", pkg_info.description);
                    if !pkg_info.depends.is_empty() {
                        println!("    Dependencies: {}", pkg_info.depends.join(", "));
                    }
                    println!();
                } else {
                    println!("  {} - Package not found", package);
                }
            }
            println!("✅ Dry run completed. No packages were actually installed.");
            return Ok(());
        }
        
        println!("🚀 REAL INSTALLATION MODE - Installing packages...");
        
        // Check authorization if needed (only for real installation)
        if apt_manager.requires_authorization("install") {
            if !apt_manager.check_authorization("install")? {
                return Err(AptOstreeError::System("Authorization required for package installation".to_string()));
            }
        }
        
        // Install packages
        let mut success_count = 0;
        let mut failure_count = 0;
        
        for package in &install_args.packages {
            println!("Installing package: {}", package);
            
            // Check if package exists
            let package_info = apt_manager.get_package_info(package)?;
            if package_info.is_none() {
                println!("  ❌ Package '{}' not found in APT repositories", package);
                failure_count += 1;
                continue;
            }
            
            // Check if already installed (for idempotent mode)
            if install_args.idempotent && apt_manager.is_package_installed(package)? {
                println!("  ⚠️  Package '{}' is already installed (idempotent mode)", package);
                success_count += 1;
                continue;
            }
            
            // Resolve dependencies
            let dependencies = apt_manager.resolve_dependencies(package)?;
            println!("  Dependencies: {} packages", dependencies.len());
            
            // Install the package
            match apt_manager.install_package(package) {
                Ok(_) => {
                    println!("  ✅ Successfully installed: {}", package);
                    success_count += 1;
                }
                Err(e) => {
                    println!("  ❌ Failed to install {}: {}", package, e);
                    failure_count += 1;
                }
            }
            println!();
        }
        
        // Summary
        println!("Install Summary:");
        println!("  Successfully installed: {} packages", success_count);
        if failure_count > 0 {
            println!("  Failed to install: {} packages", failure_count);
        }
        
        if is_ostree_system {
            println!();
            println!("Note: On OSTree systems, packages are installed as overlays");
            println!("      and will persist across system updates.");
            
            if install_args.apply_live {
                println!("Live changes have been applied to the running system.");
            }
        }
        
        if install_args.reboot {
            println!();
            println!("⚠️  Reboot requested. Please reboot the system to complete the installation.");
        }
        
        if failure_count == 0 {
            println!("✅ All packages installed successfully!");
        } else {
            println!("⚠️  Some packages could not be installed. Check the output above.");
        }
        
        Ok(())
    }
    
    fn name(&self) -> &'static str {
        "install"
    }
    
    fn description(&self) -> &'static str {
        "Overlay additional packages"
    }
    
    fn show_help(&self) {
        println!("apt-ostree install - Overlay additional packages");
        println!();
        println!("Usage: apt-ostree install <PACKAGES>... [OPTIONS]");
        println!();
        println!("Arguments:");
        println!("  PACKAGES      Package names to install");
        println!();
        println!("Options:");
        println!("  --dry-run, -d Show what would be installed without actually installing");
        println!("  --cache-only, -c Do not download latest OSTree and APT data");
        println!("  --download-only  Just download latest OSTree and APT data, don't deploy");
        println!("  --apply-live     Apply changes to both pending deployment and running filesystem tree");
        println!("  --reboot, -r     Initiate a reboot after operation is complete");
        println!("  --lock-finalization Prevent automatic deployment finalization on shutdown");
        println!("  --idempotent     Do nothing if package already installed");
        println!("  --help, -h       Show this help message");
        println!();
        println!("Examples:");
        println!("  apt-ostree install nginx");
        println!("  apt-ostree install nginx vim htop");
        println!("  apt-ostree install --dry-run nginx");
        println!("  apt-ostree install --apply-live nginx");
        println!("  apt-ostree install --reboot nginx");
        println!();
        println!("Note: On OSTree systems, packages are installed as overlays");
        println!("      and will persist across system updates.");
    }
}

/// Uninstall command - Remove overlayed additional packages
pub struct UninstallCommand;

impl UninstallCommand {
    pub fn new() -> Self {
        Self
    }
    
    /// Parse uninstall arguments from string array (private method)
    fn parse_uninstall_args(&self, args: &[String]) -> AptOstreeResult<UninstallArgs> {
        // This is a simplified parser for the string arguments
        // In a real implementation, this would use the structured CLI args directly
        let mut packages = Vec::new();
        let mut all = false;
        let mut cache_only = false;
        let mut download_only = false;
        let mut apply_live = false;
        let mut reboot = false;
        let mut lock_finalization = false;
        let mut dry_run = false;
        
        for arg in args {
            match arg.as_str() {
                "--all" => all = true,
                "--cache-only" | "-c" => cache_only = true,
                "--download-only" => download_only = true,
                "--apply-live" => apply_live = true,
                "--reboot" | "-r" => reboot = true,
                "--lock-finalization" => lock_finalization = true,
                "--dry-run" | "-d" => dry_run = true,
                "--help" | "-h" => {
                    self.show_help();
                    return Err(AptOstreeError::InvalidArgument("Help requested".to_string()));
                }
                arg if !arg.starts_with('-') => {
                    packages.push(arg.to_string());
                }
                _ => {}
            }
        }
        
        if packages.is_empty() && !all {
            return Err(AptOstreeError::InvalidArgument(
                "No packages specified and --all not used. Use --help for usage information.".to_string()
            ));
        }
        
        Ok(UninstallArgs {
            packages,
            install: None,
            all,
            cache_only,
            download_only,
            apply_live,
            force_replacefiles: false,
            stateroot: None,
            reboot,
            dry_run,
            assumeyes: false,
            allow_inactive: false,
            idempotent: false,
            unchanged_exit_77: false,
            lock_finalization,
            enablerepo: None,
            disablerepo: None,
            releasever: None,
            sysroot: None,
            peer: false,
        })
    }
}

impl Command for UninstallCommand {
    fn execute(&self, args: &[String]) -> AptOstreeResult<()> {
        // Parse the structured arguments from the CLI
        let uninstall_args = self.parse_uninstall_args(args)?;
        
        println!("🗑️  Uninstall Packages");
        println!("=====================");
        println!("Packages to remove: {}", uninstall_args.packages.join(", "));
        
        if uninstall_args.all {
            println!("Mode: Remove all overlayed packages");
        }
        if uninstall_args.cache_only {
            println!("Mode: Cache only (no download)");
        }
        if uninstall_args.download_only {
            println!("Mode: Download only (no deployment)");
        }
        if uninstall_args.apply_live {
            println!("Mode: Apply live changes");
        }
        if uninstall_args.reboot {
            println!("Mode: Reboot after operation");
        }
        if uninstall_args.lock_finalization {
            println!("Mode: Lock finalization");
        }
        if uninstall_args.dry_run {
            println!("Mode: Dry run (no actual removal)");
        }
        println!();
        
        // Check if we're on an OSTree system
        let ostree_manager = OstreeManager::new();
        let is_ostree_system = ostree_manager.is_available() && ostree_manager.is_ostree_booted();
        
        if is_ostree_system {
            println!("OSTree: System is booted from OSTree");
            println!("Mode: Package overlay removal");
        } else {
            println!("OSTree: Traditional package management system");
            println!("Mode: Standard package removal");
        }
        println!();
        
        // Use the real APT manager for package removal
        let apt_manager = AptManager::new();
        
        // Check if APT is available
        if !apt_manager.check_database_health()? {
            return Err(AptOstreeError::System("APT database is not healthy".to_string()));
        }
        
        if uninstall_args.dry_run {
            println!("🔍 DRY RUN MODE - No packages will be removed");
            println!("Dry run mode - would remove the following packages:");
            for package in &uninstall_args.packages {
                if let Ok(Some(pkg_info)) = apt_manager.get_package_info(package) {
                    println!("  {} (version: {})", pkg_info.name, pkg_info.version);
                    println!("    Description: {}", pkg_info.description);
                    if apt_manager.is_package_installed(package)? {
                        println!("    Status: Currently installed");
                    } else {
                        println!("    Status: Not currently installed");
                    }
                    println!();
                } else {
                    println!("  {} - Package not found in repositories", package);
                }
            }
            println!("✅ Dry run completed. No packages were actually removed.");
            return Ok(());
        }
        
        println!("🚀 REAL REMOVAL MODE - Removing packages...");
        
        // Check authorization if needed (only for real removal)
        if apt_manager.requires_authorization("remove") {
            if !apt_manager.check_authorization("remove")? {
                return Err(AptOstreeError::System("Authorization required for package removal".to_string()));
            }
        }
        
        // Determine packages to remove
        let packages_to_remove = if uninstall_args.all {
            // Get all installed packages (this is a simplified approach)
            // In a real implementation, you'd query the overlay database
            println!("Getting list of all installed packages...");
            vec!["*".to_string()] // Placeholder for all packages
        } else {
            uninstall_args.packages.clone()
        };
        
        // Process each package
        let mut success_count = 0;
        let mut failure_count = 0;
        
        for package in &packages_to_remove {
            if package == "*" {
                println!("Removing all overlayed packages...");
                // This would require special handling for bulk removal
                println!("  ⚠️  Bulk removal not yet implemented");
                continue;
            }
            
            println!("Removing package: {}", package);
            
            // Check if package is installed
            if !apt_manager.is_package_installed(package)? {
                println!("  Warning: Package '{}' is not installed", package);
                continue;
            }
            
            // Get package info before removal
            if let Ok(Some(pkg_info)) = apt_manager.get_package_info(package) {
                println!("  Package: {} (version: {})", pkg_info.name, pkg_info.version);
                println!("  Description: {}", pkg_info.description);
                
                // Check for reverse dependencies
                println!("  Checking dependencies...");
            }
            
            // Remove the package
            match apt_manager.remove_package(package) {
                Ok(_) => {
                    println!("  ✅ Successfully removed: {}", package);
                    success_count += 1;
                }
                Err(e) => {
                    println!("  ❌ Failed to remove {}: {}", package, e);
                    failure_count += 1;
                }
            }
            println!();
        }
        
        // Summary
        println!("Uninstall Summary:");
        println!("  Successfully removed: {} packages", success_count);
        if failure_count > 0 {
            println!("  Failed to remove: {} packages", failure_count);
        }
        
        if is_ostree_system {
            println!();
            println!("Note: On OSTree systems, package overlays have been removed.");
            println!("      The base system remains unchanged.");
            
            if uninstall_args.apply_live {
                println!("Live changes have been applied to the running system.");
            }
        }
        
        if uninstall_args.reboot {
            println!();
            println!("⚠️  Reboot requested. Please reboot the system to complete the removal.");
        }
        
        if failure_count == 0 {
            println!("✅ All packages removed successfully!");
        } else {
            println!("⚠️  Some packages could not be removed. Check the output above.");
        }
        
        Ok(())
    }
    
    fn name(&self) -> &'static str {
        "uninstall"
    }
    
    fn description(&self) -> &'static str {
        "Remove overlayed additional packages"
    }
    
    fn show_help(&self) {
        println!("apt-ostree uninstall - Remove overlayed additional packages");
        println!();
        println!("Usage: apt-ostree uninstall <PACKAGES>... [OPTIONS]");
        println!();
        println!("Arguments:");
        println!("  PACKAGES      Package names to remove");
        println!();
        println!("Options:");
        println!("  --all         Remove all overlayed additional packages");
        println!("  --cache-only, -c Do not download latest OSTree and APT data");
        println!("  --download-only  Just download latest OSTree and APT data, don't deploy");
        println!("  --apply-live     Apply changes to both pending deployment and running filesystem tree");
        println!("  --reboot, -r     Initiate a reboot after operation is complete");
        println!("  --lock-finalization Prevent automatic deployment finalization on shutdown");
        println!("  --dry-run, -d   Show what would be removed without actually removing");
        println!("  --help, -h       Show this help message");
        println!();
        println!("Examples:");
        println!("  apt-ostree uninstall nginx");
        println!("  apt-ostree uninstall nginx vim htop");
        println!("  apt-ostree uninstall --all");
        println!("  apt-ostree uninstall --apply-live nginx");
        println!("  apt-ostree uninstall --reboot nginx");
        println!();
        println!("Note: On OSTree systems, package overlays are removed.");
        println!("      The base system remains unchanged.");
    }
}

/// Search command - Search for packages
pub struct SearchCommand;

impl SearchCommand {
    pub fn new() -> Self {
        Self
    }
    
    /// Parse search arguments from string array (private method)
    fn parse_search_args(&self, args: &[String]) -> AptOstreeResult<SearchArgs> {
        // This is a simplified parser for the string arguments
        // In a real implementation, this would use the structured CLI args directly
        let mut query = String::new();
        let mut cache_only = false;
        let mut download_only = false;
        let mut apply_live = false;
        
        for arg in args {
            match arg.as_str() {
                "--cache-only" | "-c" => cache_only = true,
                "--download-only" => download_only = true,
                "--apply-live" => apply_live = true,
                "--help" | "-h" => {
                    self.show_help();
                    return Err(AptOstreeError::InvalidArgument("Help requested".to_string()));
                }
                arg if !arg.starts_with('-') => {
                    if query.is_empty() {
                        query = arg.to_string();
                    }
                }
                _ => {}
            }
        }
        
        if query.is_empty() {
            return Err(AptOstreeError::InvalidArgument(
                "No search query specified. Use --help for usage information.".to_string()
            ));
        }
        
        Ok(SearchArgs {
            query,
            uninstall: None,
            cache_only,
            download_only,
            apply_live,
            force_replacefiles: false,
            install: None,
            all: false,
            stateroot: None,
            reboot: false,
            dry_run: false,
            assumeyes: false,
            allow_inactive: false,
            idempotent: false,
            unchanged_exit_77: false,
            lock_finalization: false,
            enablerepo: None,
            disablerepo: None,
            releasever: None,
            sysroot: None,
            peer: false,
        })
    }
}

impl Command for SearchCommand {
    fn execute(&self, args: &[String]) -> AptOstreeResult<()> {
        // Parse the structured arguments from the CLI
        let search_args = self.parse_search_args(args)?;
        
        println!("🔍 Package Search");
        println!("=================");
        println!("Query: {}", search_args.query);
        println!("Mode: Standard Search");
        
        if search_args.cache_only {
            println!("Mode: Cache only (no download)");
        }
        if search_args.download_only {
            println!("Mode: Download only (no deployment)");
        }
        if search_args.apply_live {
            println!("Mode: Apply live changes");
        }
        println!();
        
        // Use the real APT manager for search
        let apt_manager = AptManager::new();
        
        // Check if APT is available
        if !apt_manager.check_database_health()? {
            return Err(AptOstreeError::System("APT database is not healthy".to_string()));
        }
        
        let packages = apt_manager.search_packages(&search_args.query)?;
        
        if packages.is_empty() {
            println!("No packages found matching '{}'", search_args.query);
            return Ok(());
        }
        
        println!("Found {} packages:", packages.len());
        println!();
        
        for package in packages {
            let status = if package.installed { "✓" } else { " " };
            println!("{} {} - {}", status, package.name, package.description);
            
            // Show basic package info
            println!("    Version: {}", package.version);
            println!("    Section: {}", package.section);
            println!("    Priority: {}", package.priority);
            if !package.depends.is_empty() {
                println!("    Dependencies: {}", package.depends.join(", "));
            }
            println!();
        }
        
        // Show additional options if available
        println!();
        println!("Search Options:");
        println!("  Use --cache-only to avoid downloading latest data");
        println!("  Use --download-only to download without deploying");
        println!("  Use --apply-live to apply changes immediately");
        
        Ok(())
    }
    
    fn name(&self) -> &'static str {
        "search"
    }
    
    fn description(&self) -> &'static str {
        "Search for packages"
    }
    
    fn show_help(&self) {
        println!("apt-ostree search - Search for packages");
        println!();
        println!("Usage: apt-ostree search <QUERY> [OPTIONS]");
        println!();
        println!("Arguments:");
        println!("  QUERY         Search query (package name or description)");
        println!();
        println!("Options:");
        println!("  --cache-only, -c Do not download latest OSTree and APT data");
        println!("  --download-only  Just download latest OSTree and APT data, don't deploy");
        println!("  --apply-live     Apply changes to both pending deployment and running filesystem tree");
        println!("  --help, -h       Show this help message");
        println!();
        println!("Examples:");
        println!("  apt-ostree search nginx");
        println!("  apt-ostree search --cache-only nginx");
        println!("  apt-ostree search --apply-live nginx");
    }
}

