//! Command modules for apt-ostree
//! 
//! This module organizes all CLI commands into logical groups for better maintainability.

pub mod system;
pub mod packages;
pub mod transactions;
pub mod advanced;
pub mod live;
pub mod utils;
pub mod experimental;
pub mod telemetry;
pub mod container;
pub mod testutils;
pub mod shlib_backend;
pub mod internals;
pub mod compose;

use apt_ostree::lib::error::AptOstreeResult;

/// Command trait that all commands must implement
#[allow(dead_code)]
pub trait Command {
    /// Execute the command with the given arguments (legacy String-based)
    fn execute(&self, args: &[String]) -> AptOstreeResult<()>;
    
    /// Get the command name
    fn name(&self) -> &'static str;
    
    /// Get the command description
    fn description(&self) -> &'static str;
    
    /// Show help for the command
    fn show_help(&self);
}

/// Trait for commands that can handle clap-based arguments
#[allow(dead_code)]
pub trait ClapCommand {
    /// Execute the command with clap-based arguments
    fn execute_with_args(&self, args: &dyn std::fmt::Debug) -> AptOstreeResult<()>;
}

/// Command registry that maps command names to implementations
#[allow(dead_code)]
pub struct CommandRegistry {
    commands: std::collections::HashMap<String, Box<dyn Command>>,
}

impl CommandRegistry {
    /// Create a new command registry with all available commands
    #[allow(dead_code)]
    pub fn new() -> Self {
        let mut registry = Self {
            commands: std::collections::HashMap::new(),
        };
        
        // Register all commands
        registry.register_commands();
        
        registry
    }
    
    /// Register all available commands
    fn register_commands(&mut self) {
        // System commands
        self.register(Box::new(system::StatusCommand::new()));
        self.register(Box::new(system::UpgradeCommand::new()));
        self.register(Box::new(system::RollbackCommand::new()));
        self.register(Box::new(system::DeployCommand::new()));
        self.register(Box::new(system::RebaseCommand::new()));
        
        // Package management commands
        self.register(Box::new(packages::InstallCommand::new()));
        self.register(Box::new(packages::UninstallCommand::new()));
        self.register(Box::new(packages::SearchCommand::new()));
        
        // System management commands
        self.register(Box::new(system::InitramfsCommand::new()));
        self.register(Box::new(system::InitramfsEtcCommand::new()));
        self.register(Box::new(system::KargsCommand::new()));
        self.register(Box::new(system::ReloadCommand::new()));
        self.register(Box::new(system::StartDaemonCommand::new()));

        
        // Transaction commands
        self.register(Box::new(transactions::TransactionCommand::new()));
        
        // Advanced commands
        self.register(Box::new(advanced::ComposeCommand::new()));
        self.register(Box::new(advanced::DbCommand::new()));
        self.register(Box::new(advanced::OverrideCommand::new()));
        self.register(Box::new(advanced::ResetCommand::new()));
        self.register(Box::new(advanced::RefreshMdCommand::new()));
        
        // Live update commands
        self.register(Box::new(live::ApplyLiveCommand::new()));
        self.register(Box::new(live::UsroverlayCommand::new()));
        
        // Utility commands
        self.register(Box::new(utils::CleanupCommand::new()));
        self.register(Box::new(utils::FinalizeDeploymentCommand::new()));
        self.register(Box::new(utils::MetricsCommand::new()));
        
        // Experimental commands
        self.register(Box::new(experimental::ExCommand::new()));
        
        // Telemetry commands
        self.register(Box::new(telemetry::CountmeCommand::new()));
        
        // Container commands
        self.register(Box::new(container::ContainerCommand::new()));
        
        // Development commands (hidden)
        self.register_development_commands();
        
        // Legacy aliases - register the same command under multiple names
        self.register_alias("update", "upgrade");
        self.register_alias("pkg-add", "install");
        self.register_alias("pkg-remove", "uninstall");
        self.register_alias("remove", "uninstall");
    }
    
    /// Register a command in the registry
    fn register(&mut self, command: Box<dyn Command>) {
        self.commands.insert(command.name().to_string(), command);
    }
    
    /// Register an alias for an existing command
    fn register_alias(&mut self, alias: &str, target_command: &str) {
        if let Some(_command) = self.commands.get(target_command) {
            // For aliases, we'll just store a reference to the existing command
            // This is a simple approach - in a real implementation you might want to clone
            // the command or use a different strategy
            let _alias_command = AliasCommand::new(alias, target_command);
            self.commands.insert(alias.to_string(), Box::new(_alias_command));
        }
    }
    
    /// Get a command by name
    #[allow(dead_code)]
    pub fn get(&self, name: &str) -> Option<&dyn Command> {
        self.commands.get(name).map(|cmd| cmd.as_ref())
    }
    
    /// List all available commands
    #[allow(dead_code)]
    pub fn list_commands(&self) -> Vec<&dyn Command> {
        self.commands.values().map(|cmd| cmd.as_ref()).collect()
    }
    
    /// Execute a command by name
    #[allow(dead_code)]
    pub fn execute(&self, name: &str, args: &[String]) -> AptOstreeResult<()> {
        if let Some(command) = self.get(name) {
            command.execute(args)
        } else {
            Err(apt_ostree::lib::error::AptOstreeError::InvalidArgument(
                format!("Unknown command: {}", name)
            ))
        }
    }

    pub fn register_development_commands(&mut self) {
        #[cfg(feature = "development")]
        {
            self.register(Box::new(testutils::TestutilsCommand::new()));
            self.register(Box::new(shlib_backend::ShlibBackendCommand::new()));
            self.register(Box::new(internals::InternalsCommand::new()));
        }
    }
}

impl Default for CommandRegistry {
    fn default() -> Self {
        Self::new()
    }
}

/// Alias command that redirects to another command
#[allow(dead_code)]
struct AliasCommand {
    alias: String,
    target: String,
}

impl AliasCommand {
    fn new(alias: &str, target: &str) -> Self {
        Self {
            alias: alias.to_string(),
            target: target.to_string(),
        }
    }
}

impl Command for AliasCommand {
    fn execute(&self, _args: &[String]) -> AptOstreeResult<()> {
        // For now, just show a message that this is an alias
        // In a real implementation, you'd want to execute the target command
        println!("Alias '{}' redirects to '{}'", self.alias, self.target);
        println!("Status: Placeholder implementation");
        println!("Next: Implement real alias redirection");
        Ok(())
    }
    
    fn name(&self) -> &'static str {
        "alias"
    }
    
    fn description(&self) -> &'static str {
        "Command alias"
    }
    
    fn show_help(&self) {
        println!("This is an alias for: {}", self.target);
    }
}
