use anyhow::Result;
use clap::{Subcommand, ValueHint};
use colored::Colorize;

use super::config::DotfileConfig;
use super::db::Database;
use super::repo::cli::{CloneArgs, RepoCommands};
use crate::ui::prelude::*;

#[derive(clap::Args, Debug, Clone, Default)]
pub struct RootFlags {
    /// Include root dotfiles (files in /)
    #[arg(long)]
    pub include_root: bool,
    /// Internal flag: only process root dotfiles
    #[arg(long, hide = true)]
    pub root_only: bool,
    /// Internal flag: override home directory
    #[arg(long, hide = true)]
    pub home: Option<String>,
}

#[derive(Subcommand, Debug)]
pub enum DotCommands {
    /// Repository management commands
    Repo {
        #[command(subcommand)]
        command: RepoCommands,
    },
    /// Clone a new repository (alias for 'repo clone')
    Clone(CloneArgs),
    Reset {
        /// Path to reset (relative to ~)
        #[arg(value_hint = ValueHint::AnyPath)]
        path: String,
        #[command(flatten)]
        root_flags: RootFlags,
    },
    /// Apply dotfiles
    Apply {
        #[command(flatten)]
        root_flags: RootFlags,
    },
    /// Add or update dotfiles
    ///
    /// For a single file: If tracked, update the source file. If untracked, prompt to add it.
    /// For a directory: Update all tracked files. Use --all to also add untracked files.
    Add {
        /// Path to add or update (relative to ~ or absolute path for root dotfiles)
        #[arg(value_hint = ValueHint::AnyPath)]
        path: String,
        /// Recursively add all files in directory, including untracked ones
        #[arg(long)]
        all: bool,
        /// Choose which repository/subdirectory to add the file to
        #[arg(long)]
        choose: bool,
        /// Override .insignore rules when adding files
        #[arg(short, long)]
        force: bool,
        /// Encrypt the file during adding to repository (adds as a .age file)
        #[arg(long)]
        encrypt: bool,
    },
    /// Convert a tracked plaintext dotfile source to age-encrypted `.age`
    Encrypt {
        /// Target path to encrypt (relative to ~ or absolute path for root dotfiles)
        #[arg(value_hint = ValueHint::AnyPath)]
        path: String,
        /// Convert the source from this repository instead of the default source
        #[arg(long, value_name = "REPO")]
        repo: Option<String>,
        /// Convert the source from this subdirectory (requires --repo)
        #[arg(long, requires = "repo", value_name = "SUBDIR")]
        subdir: Option<String>,
        /// Show what would be converted without writing files
        #[arg(long)]
        dry_run: bool,
        #[command(flatten)]
        root_flags: RootFlags,
    },
    /// Convert a tracked age-encrypted `.age` dotfile source back to plaintext
    Decrypt {
        /// Target path to decrypt (relative to ~ or absolute path for root dotfiles)
        #[arg(value_hint = ValueHint::AnyPath)]
        path: String,
        /// Convert the source from this repository instead of the default source
        #[arg(long, value_name = "REPO")]
        repo: Option<String>,
        /// Convert the source from this subdirectory (requires --repo)
        #[arg(long, requires = "repo", value_name = "SUBDIR")]
        subdir: Option<String>,
        /// Show what would be converted without writing files
        #[arg(long)]
        dry_run: bool,
        #[command(flatten)]
        root_flags: RootFlags,
    },
    /// Manage dotfile encryption keys and recipients
    Keys {
        #[command(subcommand)]
        command: EncryptCommands,
    },
    Update {
        /// Do not apply dotfiles after updating
        #[arg(long)]
        no_apply: bool,
        #[command(flatten)]
        root_flags: RootFlags,
    },
    Status {
        /// Optional path to a dotfile (target path, e.g. ~/.config/kitty/kitty.conf)
        #[arg(value_hint = ValueHint::AnyPath)]
        path: Option<String>,
        /// Show all dotfiles including clean ones
        #[arg(long)]
        all: bool,
        /// Show which repository/subdirectory each dotfile comes from
        #[arg(long)]
        show_sources: bool,
        #[command(flatten)]
        root_flags: RootFlags,
    },
    /// Initialize the current git repo or bootstrap a default dotfile repo when outside git
    Init {
        /// Optional name to set in instantdots.toml
        name: Option<String>,
        /// Run non-interactively (use provided name or directory name)
        #[arg(long)]
        non_interactive: bool,
    },
    Diff {
        /// Optional path to a dotfile (target path, e.g. ~/.config/kitty/kitty.conf)
        #[arg(value_hint = ValueHint::AnyPath)]
        path: Option<String>,
        #[command(flatten)]
        root_flags: RootFlags,
    },
    /// Merge a modified dotfile with its source using nvim diff
    Merge {
        /// Path to the dotfile (target path, e.g. ~/.config/kitty/kitty.conf)
        #[arg(value_hint = ValueHint::AnyPath)]
        path: String,
        /// Show verbose output including unmodified files
        #[arg(long)]
        verbose: bool,
    },
    /// Manage ignored paths
    Ignore {
        #[command(subcommand)]
        command: IgnoreCommands,
    },
    /// Manage dotfile units
    Unit {
        /// Manage units in a repo (defaults to global units)
        #[arg(long, value_name = "REPO")]
        repo: Option<String>,
        #[command(subcommand)]
        command: UnitCommands,
    },
    /// Commit changes in all writable repositories
    Commit {
        /// Arguments to pass to git commit (e.g. "-m 'message'")
        #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
        args: Vec<String>,
    },
    /// Push changes in all writable repositories
    Push {
        /// Arguments to pass to git push (e.g. "origin main")
        #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
        args: Vec<String>,
    },
    /// Pull changes in all writable repositories
    Pull {
        /// Arguments to pass to git pull (e.g. "--rebase")
        #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
        args: Vec<String>,
    },
    /// Run an arbitrary git command in a repository
    Git {
        /// Git command and arguments (e.g. "log --oneline")
        #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
        args: Vec<String>,
    },
    /// Set or view which repository/subdirectory a dotfile is sourced from
    Alternative {
        /// Path to the dotfile or directory (defaults to ~/ to browse all)
        #[arg(value_hint = ValueHint::AnyPath, default_value = "~")]
        path: String,
        /// Remove the override for this file (use default priority)
        #[arg(long)]
        reset: bool,
        /// Create the file in a new repo/subdir if it doesn't exist there
        #[arg(long)]
        create: bool,
        /// List available alternatives and exit
        #[arg(long)]
        list: bool,
        /// Set source to REPO or REPO/SUBDIR (non-interactive)
        #[arg(long, value_name = "REPO[/SUBDIR]")]
        set: Option<String>,
        /// Repository name (with --create for non-interactive mode)
        #[arg(long, requires = "create")]
        repo: Option<String>,
        /// Subdirectory name (with --create for non-interactive mode)
        #[arg(long, requires = "repo")]
        subdir: Option<String>,
    },
    /// Manage repository priority order
    Priority {
        #[command(subcommand)]
        command: PriorityCommands,
    },
    /// Interactive dotfile repository menu
    Menu {
        /// Open the menu in a GUI terminal window
        #[arg(long = "gui")]
        gui: bool,
    },
    /// Open a repository in lazygit (alias for 'repo lazygit')
    Lg {
        /// Repository name (optional, will prompt if not provided)
        #[arg(add = clap_complete::engine::ArgValueCompleter::new(crate::completions::repo_name_completion))]
        name: Option<String>,
    },
    /// Delete a tracked dotfile (removes from repo, home directory, and database)
    Delete {
        /// Path to the dotfile to delete (omit for interactive picker)
        #[arg(value_hint = ValueHint::AnyPath)]
        path: Option<String>,
        /// Delete all tracked dotfiles under a directory
        #[arg(long, short)]
        recursive: bool,
        /// Show what would be deleted without actually deleting
        #[arg(long)]
        dry_run: bool,
    },
}

#[derive(Subcommand, Debug)]
pub enum IgnoreCommands {
    /// Add a path to the ignore list
    Add {
        /// Path to ignore (relative to ~, e.g., .config/nvim or .bashrc)
        #[arg(value_hint = ValueHint::AnyPath)]
        path: String,
    },
    /// Remove a path from the ignore list
    Remove {
        /// Path to stop ignoring
        #[arg(value_hint = ValueHint::AnyPath)]
        path: String,
    },
    /// List all ignored paths
    List,
}

#[derive(Subcommand, Debug)]
pub enum UnitCommands {
    /// Add a unit directory (relative to ~)
    Add {
        #[arg(value_hint = ValueHint::AnyPath)]
        path: String,
    },
    /// Remove a unit directory
    Remove {
        #[arg(value_hint = ValueHint::AnyPath)]
        path: String,
    },
    /// List configured unit directories
    List,
}

#[derive(Subcommand, Debug)]
pub enum PriorityCommands {
    /// Increase repository priority (move earlier in list)
    Bump {
        /// Repository name
        #[arg(add = clap_complete::engine::ArgValueCompleter::new(crate::completions::repo_name_completion))]
        name: String,
    },
    /// Decrease repository priority (move later in list)
    Lower {
        /// Repository name
        #[arg(add = clap_complete::engine::ArgValueCompleter::new(crate::completions::repo_name_completion))]
        name: String,
    },
    /// Set repository to a specific priority position
    Set {
        /// Repository name
        #[arg(add = clap_complete::engine::ArgValueCompleter::new(crate::completions::repo_name_completion))]
        name: String,
        /// Priority position (1 = highest priority)
        position: usize,
    },
    /// List repositories in priority order
    List,
}

#[derive(Subcommand, Debug, Clone)]
pub enum EncryptCommands {
    /// Generate a new encryption key for this machine
    Generate {
        /// Name for the new key (stored in ~/.config/instant/encryption/identities/<name>)
        #[arg(long)]
        name: Option<String>,
        /// Force generation even if a key with this name already exists
        #[arg(long)]
        force: bool,
    },
    /// List all local encryption keys
    List,
    /// Rename an encryption key
    Rename {
        /// Current key name
        old_name: String,
        /// New key name
        new_name: String,
    },
    /// Remove an encryption key
    Remove {
        /// Key name to remove
        name: String,
    },
    /// Authorize a new encryption recipient public key in the repository metadata
    Authorize {
        /// Public key to authorize (age1... or ssh-...). Defaults to the local machine's public key.
        recipient: Option<String>,
        /// Add recipient to this repository instead of the default repo
        #[arg(long, value_name = "REPO")]
        repo: Option<String>,
        /// Show what would be done without writing any changes
        #[arg(long)]
        dry_run: bool,
        #[command(flatten)]
        root_flags: RootFlags,
    },
    /// De-authorize a recipient key from a repository
    Deauthorize {
        /// Public key to de-authorize (age1... or ssh-...)
        recipient: String,
        /// Remove recipient from this repository instead of the default repo
        #[arg(long, value_name = "REPO")]
        repo: Option<String>,
        /// Show what would be done without writing any changes
        #[arg(long)]
        dry_run: bool,
        #[command(flatten)]
        root_flags: RootFlags,
    },
    /// Rotate all keys in a repository with a new set of recipients
    Rotate {
        /// New comma-separated list of encryption recipients (overwrites old recipients)
        #[arg(long, value_delimiter = ',')]
        recipients: Vec<String>,
        /// Rotate keys in this repository instead of the default repo
        #[arg(long, value_name = "REPO")]
        repo: Option<String>,
        /// Show what would be done without writing any changes
        #[arg(long)]
        dry_run: bool,
        #[command(flatten)]
        root_flags: RootFlags,
    },
    /// List authorized recipients and check local key decryption status
    Status {
        /// Check keys for this repository instead of all repositories
        #[arg(long, value_name = "REPO")]
        repo: Option<String>,
        #[command(flatten)]
        root_flags: RootFlags,
    },
    /// Show the local public encryption key for this machine
    Show,
}

fn handle_ignore_command(
    config: &mut DotfileConfig,
    command: &IgnoreCommands,
    config_path: Option<&str>,
) -> Result<()> {
    match command {
        IgnoreCommands::Add { path } => {
            let normalized_path = crate::dot::utils::normalize_path_to_tilde(path);

            config.add_ignored_path(normalized_path.clone(), config_path)?;
            emit(
                Level::Success,
                "dot.ignore.added",
                &format!(
                    "{} Added {} to ignore list",
                    char::from(NerdFont::Check),
                    normalized_path.green()
                ),
                Some(serde_json::json!({
                    "path": normalized_path,
                    "action": "added"
                })),
            );
        }
        IgnoreCommands::Remove { path } => {
            let normalized_path = crate::dot::utils::normalize_path_to_tilde(path);

            // Validate that absolute paths are under home
            if path.starts_with('/') && !normalized_path.starts_with('~') {
                return Err(anyhow::anyhow!(
                    "Path must be within home directory. Use ~ or relative paths."
                ));
            }

            config.remove_ignored_path(&normalized_path, config_path)?;
            emit(
                Level::Success,
                "dot.ignore.removed",
                &format!(
                    "{} Removed {} from ignore list",
                    char::from(NerdFont::Check),
                    normalized_path.green()
                ),
                Some(serde_json::json!({
                    "path": normalized_path,
                    "action": "removed"
                })),
            );
        }
        IgnoreCommands::List => {
            if config.ignored_paths.is_empty() {
                emit(
                    Level::Info,
                    "dot.ignore.list.empty",
                    &format!(
                        "{} No paths are currently ignored",
                        char::from(NerdFont::Info)
                    ),
                    None,
                );
            } else {
                emit(
                    Level::Info,
                    "dot.ignore.list.header",
                    &format!("{} Ignored paths:", char::from(NerdFont::List)),
                    Some(serde_json::json!({
                        "count": config.ignored_paths.len()
                    })),
                );
                for (i, path) in config.ignored_paths.iter().enumerate() {
                    emit(
                        Level::Info,
                        "dot.ignore.list.item",
                        &format!("  {} {}", (i + 1), path.cyan()),
                        Some(serde_json::json!({
                            "index": i + 1,
                            "path": path
                        })),
                    );
                }
            }
        }
    }

    Ok(())
}

fn handle_unit_command(
    config: &mut DotfileConfig,
    db: &Database,
    command: &UnitCommands,
    repo: Option<&str>,
    config_path: Option<&str>,
) -> Result<()> {
    let scope = match repo {
        Some(name) => crate::dot::unit_manager::UnitScope::Repo(name.to_string()),
        None => crate::dot::unit_manager::UnitScope::Global,
    };
    let context = crate::dot::unit_manager::unit_path_context_for_write(&scope, config, db)?;

    match command {
        UnitCommands::Add { path } => {
            let normalized_path = crate::dot::unit_manager::normalize_unit_input(path, &context)?;
            crate::dot::unit_manager::add_unit(&scope, config, db, &normalized_path, config_path)?;
            emit(
                Level::Success,
                "dot.unit.added",
                &format!(
                    "{} Added {} to units",
                    char::from(NerdFont::Check),
                    normalized_path.green()
                ),
                Some(serde_json::json!({
                    "path": normalized_path,
                    "action": "added",
                    "scope": scope_label(&scope)
                })),
            );
        }
        UnitCommands::Remove { path } => {
            let normalized_path = crate::dot::unit_manager::normalize_unit_input(path, &context)?;
            crate::dot::unit_manager::remove_unit(
                &scope,
                config,
                db,
                &normalized_path,
                config_path,
            )?;
            emit(
                Level::Success,
                "dot.unit.removed",
                &format!(
                    "{} Removed {} from units",
                    char::from(NerdFont::Check),
                    normalized_path.green()
                ),
                Some(serde_json::json!({
                    "path": normalized_path,
                    "action": "removed",
                    "scope": scope_label(&scope)
                })),
            );
        }
        UnitCommands::List => {
            let units = crate::dot::unit_manager::list_units(&scope, config, db)?;
            if units.is_empty() {
                emit(
                    Level::Info,
                    "dot.unit.list.empty",
                    &format!(
                        "{} No unit directories configured",
                        char::from(NerdFont::Info)
                    ),
                    None,
                );
            } else {
                emit(
                    Level::Info,
                    "dot.unit.list.header",
                    &format!("{} Unit directories:", char::from(NerdFont::List)),
                    Some(serde_json::json!({
                        "count": units.len(),
                        "scope": scope_label(&scope)
                    })),
                );
                for (i, unit) in units.iter().enumerate() {
                    emit(
                        Level::Info,
                        "dot.unit.list.item",
                        &format!("  {} {}", i + 1, unit.cyan()),
                        Some(serde_json::json!({
                            "index": i + 1,
                            "path": unit,
                            "scope": scope_label(&scope)
                        })),
                    );
                }
            }
        }
    }

    Ok(())
}

fn scope_label(scope: &crate::dot::unit_manager::UnitScope) -> String {
    scope.to_string()
}

fn handle_priority_command(
    config: &mut DotfileConfig,
    command: &PriorityCommands,
    config_path: Option<&str>,
) -> Result<()> {
    match command {
        PriorityCommands::Bump { name } => {
            let new_pos = config.move_repo_up(name, config_path)?;
            emit(
                Level::Success,
                "dot.priority.bump",
                &format!(
                    "{} Moved repository '{}' up to priority P{}",
                    char::from(NerdFont::Check),
                    name.cyan(),
                    new_pos
                ),
                Some(serde_json::json!({
                    "name": name,
                    "new_priority": new_pos
                })),
            );
        }
        PriorityCommands::Lower { name } => {
            let new_pos = config.move_repo_down(name, config_path)?;
            emit(
                Level::Success,
                "dot.priority.lower",
                &format!(
                    "{} Moved repository '{}' down to priority P{}",
                    char::from(NerdFont::Check),
                    name.cyan(),
                    new_pos
                ),
                Some(serde_json::json!({
                    "name": name,
                    "new_priority": new_pos
                })),
            );
        }
        PriorityCommands::Set { name, position } => {
            config.set_repo_priority(name, *position, config_path)?;
            emit(
                Level::Success,
                "dot.priority.set",
                &format!(
                    "{} Set repository '{}' to priority P{}",
                    char::from(NerdFont::Check),
                    name.cyan(),
                    position
                ),
                Some(serde_json::json!({
                    "name": name,
                    "priority": position
                })),
            );
        }
        PriorityCommands::List => {
            if config.repos.is_empty() {
                emit(
                    Level::Info,
                    "dot.priority.list.empty",
                    &format!("{} No repositories configured", char::from(NerdFont::Info)),
                    None,
                );
            } else {
                emit(
                    Level::Info,
                    "dot.priority.list.header",
                    &format!(
                        "{} Repository priority order (first = highest):",
                        char::from(NerdFont::List)
                    ),
                    None,
                );
                for (i, repo) in config.repos.iter().enumerate() {
                    let priority = format!("[P{}]", i + 1).bright_purple().bold();
                    let status = if repo.enabled {
                        "".to_string()
                    } else {
                        " (disabled)".yellow().to_string()
                    };
                    emit(
                        Level::Info,
                        "dot.priority.list.item",
                        &format!("  {} {}{}", priority, repo.name.cyan(), status),
                        Some(serde_json::json!({
                            "priority": i + 1,
                            "name": repo.name,
                            "enabled": repo.enabled
                        })),
                    );
                }
            }
        }
    }

    Ok(())
}

pub fn handle_dot_command(
    command: &DotCommands,
    config_path: Option<&str>,
    debug: bool,
) -> Result<()> {
    let home_override = match command {
        DotCommands::Reset { root_flags, .. }
        | DotCommands::Apply { root_flags, .. }
        | DotCommands::Encrypt { root_flags, .. }
        | DotCommands::Decrypt { root_flags, .. }
        | DotCommands::Update { root_flags, .. }
        | DotCommands::Status { root_flags, .. }
        | DotCommands::Diff { root_flags, .. } => root_flags.home.as_deref(),
        DotCommands::Keys {
            command:
                EncryptCommands::Authorize { root_flags, .. }
                | EncryptCommands::Rotate { root_flags, .. }
                | EncryptCommands::Status { root_flags, .. },
        } => root_flags.home.as_deref(),
        DotCommands::Keys { .. } => None,
        DotCommands::Clone(args) => args.root_flags.home.as_deref(),
        DotCommands::Repo {
            command: RepoCommands::Clone(args),
        } => args.root_flags.home.as_deref(),
        _ => None,
    };

    if let Some(home_path) = home_override {
        unsafe {
            std::env::set_var("HOME", home_path);
        }
    }

    let mut config = DotfileConfig::load(config_path)?;
    config.ensure_directories()?;
    let db = Database::new(config.database_path().to_path_buf())?;

    match command {
        DotCommands::Repo { command } => {
            super::repo::commands::handle_repo_command(&mut config, &db, command, debug)?;
        }
        DotCommands::Clone(args) => {
            super::repo::commands::handle_repo_command(
                &mut config,
                &db,
                &RepoCommands::Clone(args.clone()),
                debug,
            )?;
        }
        DotCommands::Reset {
            path, root_flags, ..
        } => {
            super::reset_modified(
                &config,
                &db,
                path,
                root_flags.include_root,
                root_flags.root_only,
            )?;
        }
        DotCommands::Apply { root_flags, .. } => {
            super::apply_all(&config, &db, root_flags.include_root, root_flags.root_only)?;
        }
        DotCommands::Add {
            path,
            all,
            choose,
            force,
            encrypt,
        } => {
            // Auto-detect root path handling is inside add_dotfile.
            // include_root parameter is removed from CLI args for add.
            // We pass true here to allow adding root files, since Add should handle both automatically.
            super::add_dotfile(
                &config, &db, path, *all, *choose, *force, *encrypt,
                true, // include_root = true allows absolute paths outside home
                debug,
            )?;
        }
        DotCommands::Encrypt {
            path,
            repo,
            subdir,
            dry_run,
            root_flags,
        } => {
            super::encrypt_dotfile(
                &config,
                &db,
                path,
                repo.as_deref(),
                subdir.as_deref(),
                *dry_run,
                root_flags.include_root,
                debug,
            )?;
        }
        DotCommands::Decrypt {
            path,
            repo,
            subdir,
            dry_run,
            root_flags,
        } => {
            super::decrypt_dotfile(
                &config,
                &db,
                path,
                repo.as_deref(),
                subdir.as_deref(),
                *dry_run,
                root_flags.include_root,
                debug,
            )?;
        }
        DotCommands::Update {
            no_apply,
            root_flags,
            ..
        } => {
            // update_all might not accept root_only, let's just pass include_root to it.
            // If root_only is true, maybe we just run apply_all?
            if root_flags.root_only {
                super::apply_all(&config, &db, root_flags.include_root, root_flags.root_only)?;
            } else {
                super::update_all(&config, debug, &db, !*no_apply, root_flags.include_root)?;
            }
        }
        DotCommands::Status {
            path,
            all,
            show_sources,
            root_flags,
            ..
        } => {
            super::status_all(
                &config,
                path.as_deref(),
                &db,
                *all,
                *show_sources,
                root_flags.include_root,
            )?;
        }
        DotCommands::Init {
            name,
            non_interactive,
        } => {
            let cwd = std::env::current_dir()
                .map_err(|e| anyhow::anyhow!("Unable to determine current directory: {}", e))?;
            super::meta::handle_init_command(&mut config, &cwd, name.as_deref(), *non_interactive)?;
        }
        DotCommands::Diff {
            path, root_flags, ..
        } => {
            super::diff_all(&config, path.as_deref(), &db, root_flags.include_root)?;
        }
        DotCommands::Merge { path, verbose } => {
            super::operations::merge::merge_dotfile(&config, &db, path, *verbose)?;
        }
        DotCommands::Ignore { command } => {
            handle_ignore_command(&mut config, command, config_path)?;
        }
        DotCommands::Unit { repo, command } => {
            handle_unit_command(&mut config, &db, command, repo.as_deref(), config_path)?;
        }
        DotCommands::Commit { args } => {
            super::git_commit_all(&config, args, debug)?;
        }
        DotCommands::Push { args } => {
            super::git_push_all(&config, args, debug)?;
        }
        DotCommands::Pull { args } => {
            let pulled_commits = super::git_pull_all(&config, args, debug)?;
            if pulled_commits {
                println!();
                super::status_all(&config, None, &db, false, false, false)?;
                println!(
                    "\n{} New commits were pulled. Use {} to apply the changes.",
                    char::from(NerdFont::Info).to_string().blue(),
                    "ins dot apply".green()
                );
            }
        }
        DotCommands::Git { args } => {
            super::git_run_any(&config, args, debug)?;
        }
        DotCommands::Alternative {
            path,
            reset,
            create,
            list,
            set,
            repo,
            subdir,
        } => {
            super::operations::alternative::handle_alternative(
                &config,
                super::operations::alternative::AlternativeOptions {
                    path,
                    reset: *reset,
                    create: *create,
                    list: *list,
                    set: set.as_deref(),
                    repo: repo.as_deref(),
                    subdir: subdir.as_deref(),
                },
            )?;
        }
        DotCommands::Priority { command } => {
            handle_priority_command(&mut config, command, config_path)?;
        }
        DotCommands::Keys { command } => {
            super::handle_encrypt_command(&config, &db, command, debug)?;
        }
        DotCommands::Menu { gui } => {
            if *gui {
                return crate::common::terminal::launch_menu_in_terminal(
                    "dot",
                    "Dotfile Menu",
                    &[],
                    debug,
                );
            }
            super::menu::dot_menu(debug)?;
        }
        DotCommands::Lg { name } => {
            super::repo::commands::interactive::open_repo_lazygit(&config, &db, name.as_deref())?;
        }
        DotCommands::Delete {
            path,
            recursive,
            dry_run,
        } => {
            super::operations::delete::delete_dotfiles(
                &config,
                &db,
                path.as_deref(),
                *recursive,
                *dry_run,
                debug,
            )?;
        }
    }

    Ok(())
}
