use anyhow::{bail, Result};
use clap::{Parser, Subcommand};
use colored::Colorize;
use dialoguer::{Confirm, Input, Select};
use std::path::PathBuf;

use crate::config::manager::ConfigManager;
use crate::config::{GitProfile, TokenConfig, TokenType};
use crate::config::profile::{GpgConfig, SshConfig};
use crate::git::find_repo;
use crate::utils::validators::validate_profile_name;

/// Manage Git profiles
#[derive(Parser)]
pub struct ProfileCommand {
    #[command(subcommand)]
    command: Option<ProfileSubcommand>,
}

#[derive(Subcommand)]
enum ProfileSubcommand {
    /// Add a new profile
    Add,
    
    /// Remove a profile
    Remove {
        /// Profile name
        name: String,
    },
    
    /// List all profiles
    List,
    
    /// Show profile details
    Show {
        /// Profile name
        name: Option<String>,
    },
    
    /// Edit a profile
    Edit {
        /// Profile name
        name: String,
    },
    
    /// Set default profile
    SetDefault {
        /// Profile name
        name: String,
    },
    
    /// Set profile for current repository
    SetRepo {
        /// Profile name
        name: String,
    },
    
    /// Apply profile to current repository
    Apply {
        /// Profile name (uses default if not specified)
        name: Option<String>,
        
        /// Apply globally instead of to current repo
        #[arg(short, long)]
        global: bool,
    },
    
    /// Switch between profiles interactively
    Switch,
    
    /// Copy/duplicate a profile
    Copy {
        /// Source profile name
        from: String,
        
        /// New profile name
        to: String,
    },
    
    /// Manage tokens for a profile
    Token {
        #[command(subcommand)]
        token_command: TokenSubcommand,
    },
    
    /// Check profile configuration against git
    Check {
        /// Profile name
        name: Option<String>,
    },
    
    /// Show usage statistics
    Stats {
        /// Profile name
        name: Option<String>,
    },
}

#[derive(Subcommand)]
enum TokenSubcommand {
    /// Add a token to a profile
    Add {
        /// Profile name
        profile: String,
        
        /// Service name (e.g., github, gitlab)
        service: String,
    },
    
    /// Remove a token from a profile
    Remove {
        /// Profile name
        profile: String,
        
        /// Service name
        service: String,
    },
    
    /// List tokens in a profile
    List {
        /// Profile name
        profile: String,
    },
}

impl ProfileCommand {
    pub async fn execute(&self, config_path: Option<PathBuf>) -> Result<()> {
        match &self.command {
            Some(ProfileSubcommand::Add) => self.add_profile(&config_path).await,
            Some(ProfileSubcommand::Remove { name }) => self.remove_profile(name, &config_path).await,
            Some(ProfileSubcommand::List) => self.list_profiles(&config_path).await,
            Some(ProfileSubcommand::Show { name }) => self.show_profile(name.as_deref(), &config_path).await,
            Some(ProfileSubcommand::Edit { name }) => self.edit_profile(name, &config_path).await,
            Some(ProfileSubcommand::SetDefault { name }) => self.set_default(name, &config_path).await,
            Some(ProfileSubcommand::SetRepo { name }) => self.set_repo(name, &config_path).await,
            Some(ProfileSubcommand::Apply { name, global }) => self.apply_profile(name.as_deref(), *global, &config_path).await,
            Some(ProfileSubcommand::Switch) => self.switch_profile(&config_path).await,
            Some(ProfileSubcommand::Copy { from, to }) => self.copy_profile(from, to, &config_path).await,
            Some(ProfileSubcommand::Token { token_command }) => self.handle_token_command(token_command, &config_path).await,
            Some(ProfileSubcommand::Check { name }) => self.check_profile(name.as_deref(), &config_path).await,
            Some(ProfileSubcommand::Stats { name }) => self.show_stats(name.as_deref(), &config_path).await,
            None => self.list_profiles(&config_path).await,
        }
    }

    fn get_manager(&self, config_path: &Option<PathBuf>) -> Result<ConfigManager> {
        match config_path {
            Some(path) => ConfigManager::with_path(path),
            None => ConfigManager::new(),
        }
    }

    async fn add_profile(&self, config_path: &Option<PathBuf>) -> Result<()> {
        let mut manager = self.get_manager(config_path)?;

        println!("{}", "\nAdd new profile".bold());
        println!("{}", "─".repeat(40));

        let name: String = Input::new()
            .with_prompt("Profile name")
            .validate_with(|input: &String| {
                validate_profile_name(input).map_err(|e| e.to_string())
            })
            .interact_text()?;

        if manager.has_profile(&name) {
            bail!("Profile '{}' already exists", name);
        }

        let user_name: String = Input::new()
            .with_prompt("Git user name")
            .interact_text()?;

        let user_email: String = Input::new()
            .with_prompt("Git user email")
            .validate_with(|input: &String| {
                crate::utils::validators::validate_email(input).map_err(|e| e.to_string())
            })
            .interact_text()?;

        let description: String = Input::new()
            .with_prompt("Description (optional)")
            .allow_empty(true)
            .interact_text()?;

        let is_work = Confirm::new()
            .with_prompt("Is this a work profile?")
            .default(false)
            .interact()?;

        let organization = if is_work {
            Some(Input::new()
                .with_prompt("Organization")
                .interact_text()?)
        } else {
            None
        };

        let mut profile = GitProfile::new(name.clone(), user_name, user_email);
        
        if !description.is_empty() {
            profile.description = Some(description);
        }
        profile.is_work = is_work;
        profile.organization = organization;

        let setup_ssh = Confirm::new()
            .with_prompt("Configure SSH key?")
            .default(false)
            .interact()?;

        if setup_ssh {
            profile.ssh = Some(self.setup_ssh_interactive().await?);
        }

        let setup_gpg = Confirm::new()
            .with_prompt("Configure GPG signing?")
            .default(false)
            .interact()?;

        if setup_gpg {
            profile.gpg = Some(self.setup_gpg_interactive().await?);
        }

        let setup_token = Confirm::new()
            .with_prompt("Add a Personal Access Token?")
            .default(false)
            .interact()?;

        if setup_token {
            self.setup_token_interactive(&mut profile, &manager).await?;
        }

        manager.add_profile(name.clone(), profile)?;
        manager.save()?;

        println!("{} Profile '{}' added successfully", "✓".green(), name.cyan());

        if manager.default_profile().is_none() {
            let set_default = Confirm::new()
                .with_prompt("Set as default profile?")
                .default(true)
                .interact()?;

            if set_default {
                manager.set_default_profile(Some(name.clone()))?;
                manager.save()?;
                println!("{} Set '{}' as default profile", "✓".green(), name.cyan());
            }
        }

        Ok(())
    }

    async fn remove_profile(&self, name: &str, config_path: &Option<PathBuf>) -> Result<()> {
        let mut manager = self.get_manager(config_path)?;

        if !manager.has_profile(name) {
            bail!("Profile '{}' not found", name);
        }

        let confirm = Confirm::new()
            .with_prompt(format!("Are you sure you want to remove profile '{}'?", name))
            .default(false)
            .interact()?;

        if !confirm {
            println!("{}", "Cancelled.".yellow());
            return Ok(());
        }

        manager.delete_all_pats_for_profile(name)?;
        
        manager.remove_profile(name)?;
        manager.save()?;

        println!("{} Profile '{}' removed (including all stored tokens)", "✓".green(), name);

        Ok(())
    }

    async fn list_profiles(&self, config_path: &Option<PathBuf>) -> Result<()> {
        let manager = self.get_manager(config_path)?;

        let profiles = manager.list_profiles();
        
        if profiles.is_empty() {
            println!("{}", "No profiles configured.".yellow());
            println!("Run {} to create one.", "quicommit profile add".cyan());
            return Ok(());
        }

        let default = manager.default_profile_name();

        println!("{}", "\nConfigured profiles:".bold());
        println!("{}", "─".repeat(60));

        for name in profiles {
            let profile = manager.get_profile(name).unwrap();
            let is_default = default.map(|d| d == name).unwrap_or(false);
            
            let marker = if is_default { "●".green() } else { "○".dimmed() };
            let work_marker = if profile.is_work { " [work]".yellow() } else { "".normal() };
            
            println!("{} {}{}", marker, name.cyan().bold(), work_marker);
            println!("   {} <{}>", profile.user_name, profile.user_email);
            
            if let Some(ref desc) = profile.description {
                println!("   {}", desc.dimmed());
            }
            
            if profile.has_ssh() {
                println!("   {} SSH configured", "🔑".to_string().dimmed());
            }
            if profile.has_gpg() {
                println!("   {} GPG configured", "🔒".to_string().dimmed());
            }
            if profile.has_tokens() {
                println!("   {} {} token(s)", "🔐".to_string().dimmed(), profile.tokens.len());
            }
            
            if let Some(ref usage) = profile.usage.last_used {
                println!("   {} Last used: {}", "📊".to_string().dimmed(), usage.dimmed());
            }
            
            println!();
        }

        Ok(())
    }

    async fn show_profile(&self, name: Option<&str>, config_path: &Option<PathBuf>) -> Result<()> {
        let manager = self.get_manager(config_path)?;

        match find_repo(std::env::current_dir()?.as_path()) {
            Ok(repo) => {
                self.show_repo_status(&repo, &manager, name).await
            }
            Err(_) => {
                self.show_global_status(&manager, name).await
            }
        }
    }

    async fn show_repo_status(&self, repo: &crate::git::GitRepo, manager: &ConfigManager, name: Option<&str>) -> Result<()> {
        use crate::git::MergedUserConfig;

        let merged_config = MergedUserConfig::from_repo(repo.inner())?;
        let repo_path = repo.path().to_string_lossy().to_string();

        println!("{}", "\n📁 Current Repository Status".bold());
        println!("{}", "─".repeat(60));
        println!("Repository: {}", repo_path.cyan());

        println!("\n{}", "Git User Configuration (merged local/global):".bold());
        println!("{}", "─".repeat(60));

        self.print_config_entry("User name", &merged_config.name);
        self.print_config_entry("User email", &merged_config.email);
        self.print_config_entry("Signing key", &merged_config.signing_key);
        self.print_config_entry("SSH command", &merged_config.ssh_command);
        self.print_config_entry("Commit GPG sign", &merged_config.commit_gpgsign);
        self.print_config_entry("Tag GPG sign", &merged_config.tag_gpgsign);

        let user_name = merged_config.name.value.clone().unwrap_or_default();
        let user_email = merged_config.email.value.clone().unwrap_or_default();
        let signing_key = merged_config.signing_key.value.as_deref();

        let matching_profile = manager.find_matching_profile(&user_name, &user_email, signing_key);
        let repo_profile_name = manager.get_repo_profile_name(&repo_path);

        println!("\n{}", "QuiCommit Profile Status:".bold());
        println!("{}", "─".repeat(60));

        match (&matching_profile, repo_profile_name) {
            (Some(profile), Some(mapped_name)) => {
                if profile.name == *mapped_name {
                    println!("{} Profile '{}' is mapped to this repository", "✓".green(), profile.name.cyan());
                    println!("  This repository's git config matches the saved profile.");
                } else {
                    println!("{} Profile '{}' matches current config", "✓".green(), profile.name.cyan());
                    println!("  But repository is mapped to different profile: {}", mapped_name.yellow());
                }
            }
            (Some(profile), None) => {
                println!("{} Profile '{}' matches current config", "✓".green(), profile.name.cyan());
                println!("  {} This repository is not mapped to any profile.", "ℹ".yellow());
            }
            (None, Some(mapped_name)) => {
                println!("{} Repository is mapped to profile '{}'", "⚠".yellow(), mapped_name.cyan());
                println!("  But current git config does not match this profile!");
                
                if let Some(mapped_profile) = manager.get_profile(mapped_name) {
                    println!("\n  Mapped profile config:");
                    println!("    user.name:  {}", mapped_profile.user_name);
                    println!("    user.email: {}", mapped_profile.user_email);
                }
            }
            (None, None) => {
                println!("{} No matching profile found in QuiCommit", "✗".red());
                println!("  Current git identity is not saved as a QuiCommit profile.");
                
                let partial_matches = manager.find_partial_matches(&user_name, &user_email);
                if !partial_matches.is_empty() {
                    println!("\n  {} Similar profiles exist:", "ℹ".yellow());
                    for p in partial_matches {
                        let same_name = p.user_name == user_name;
                        let same_email = p.user_email == user_email;
                        let reason = match (same_name, same_email) {
                            (true, true) => "same name & email",
                            (true, false) => "same name",
                            (false, true) => "same email",
                            (false, false) => "partial match",
                        };
                        println!("    - {} ({})", p.name.cyan(), reason.dimmed());
                    }
                }

                if merged_config.is_complete() {
                    println!("\n  {} Would you like to save this identity as a new profile?", "💡".yellow());
                    let save = Confirm::new()
                        .with_prompt("Save current git identity as new profile?")
                        .default(true)
                        .interact()?;

                    if save {
                        self.save_current_identity_as_profile(&merged_config, manager).await?;
                    }
                }
            }
        }

        if let Some(profile_name) = name {
            if let Some(profile) = manager.get_profile(profile_name) {
                println!("\n{}", format!("Requested Profile: {}", profile_name).bold());
                println!("{}", "─".repeat(60));
                self.print_profile_details(profile);
            } else {
                println!("\n{} Profile '{}' not found", "✗".red(), profile_name);
            }
        } else if let Some(profile) = manager.default_profile() {
            println!("\n{}", format!("Default Profile: {}", profile.name).bold());
            println!("{}", "─".repeat(60));
            self.print_profile_details(profile);
        }

        Ok(())
    }

    async fn show_global_status(&self, manager: &ConfigManager, name: Option<&str>) -> Result<()> {
        println!("{}", "\n⚠ Not in a Git Repository".bold().yellow());
        println!("{}", "─".repeat(60));
        println!("Run this command inside a git repository to see local config status.");
        println!();

        if let Some(profile_name) = name {
            if let Some(profile) = manager.get_profile(profile_name) {
                println!("{}", format!("Profile: {}", profile_name).bold());
                println!("{}", "─".repeat(40));
                self.print_profile_details(profile);
            } else {
                bail!("Profile '{}' not found", profile_name);
            }
        } else if let Some(profile) = manager.default_profile() {
            println!("{}", format!("Default Profile: {}", profile.name).bold());
            println!("{}", "─".repeat(40));
            self.print_profile_details(profile);
        } else {
            println!("{}", "No default profile set.".yellow());
            println!("Run {} to create one.", "quicommit profile add".cyan());
        }

        Ok(())
    }

    fn print_config_entry(&self, label: &str, entry: &crate::git::ConfigEntry) {
        use crate::git::ConfigSource;

        let source_indicator = match entry.source {
            ConfigSource::Local => format!("[{}]", "local".green()),
            ConfigSource::Global => format!("[{}]", "global".blue()),
            ConfigSource::NotSet => format!("[{}]", "not set".dimmed()),
        };

        match &entry.value {
            Some(value) => {
                println!("{} {}: {}", source_indicator, label, value);
                if entry.local_value.is_some() && entry.global_value.is_some() {
                    println!("    {} local: {}", "├".dimmed(), entry.local_value.as_ref().unwrap());
                    println!("    {} global: {}", "└".dimmed(), entry.global_value.as_ref().unwrap());
                }
            }
            None => {
                println!("{} {}: {}", source_indicator, label, "<not set>".dimmed());
            }
        }
    }

    fn print_profile_details(&self, profile: &GitProfile) {
        println!("User name:  {}", profile.user_name);
        println!("User email: {}", profile.user_email);
        
        if let Some(ref desc) = profile.description {
            println!("Description: {}", desc);
        }
        
        println!("Work profile: {}", if profile.is_work { "yes".yellow() } else { "no".normal() });
        
        if let Some(ref org) = profile.organization {
            println!("Organization: {}", org);
        }

        if let Some(ref ssh) = profile.ssh {
            println!("\n{}", "SSH Configuration:".bold());
            if let Some(ref path) = ssh.private_key_path {
                println!("  Private key: {:?}", path);
            }
        }

        if let Some(ref gpg) = profile.gpg {
            println!("\n{}", "GPG Configuration:".bold());
            println!("  Key ID: {}", gpg.key_id);
            println!("  Program: {}", gpg.program);
            println!("  Use agent: {}", if gpg.use_agent { "yes" } else { "no" });
        }

        if !profile.tokens.is_empty() {
            println!("\n{}", "Tokens:".bold());
            for (service, token) in &profile.tokens {
                println!("  {} ({})", service.cyan(), token.token_type);
                if let Some(ref desc) = token.description {
                    println!("    {}", desc);
                }
            }
        }

        if profile.usage.total_uses > 0 {
            println!("\n{}", "Usage Statistics:".bold());
            println!("  Total uses: {}", profile.usage.total_uses);
            if let Some(ref last_used) = profile.usage.last_used {
                println!("  Last used: {}", last_used);
            }
        }
    }

    async fn save_current_identity_as_profile(&self, merged_config: &crate::git::MergedUserConfig, manager: &ConfigManager) -> Result<()> {
        let config_path = manager.path().to_path_buf();
        let mut manager = ConfigManager::with_path(&config_path)?;

        let user_name = merged_config.name.value.clone().unwrap_or_default();
        let user_email = merged_config.email.value.clone().unwrap_or_default();

        println!("\n{}", "Save New Profile".bold());
        println!("{}", "─".repeat(40));

        let default_name = user_name.to_lowercase().replace(' ', "-");
        let profile_name: String = Input::new()
            .with_prompt("Profile name")
            .default(default_name)
            .validate_with(|input: &String| {
                validate_profile_name(input).map_err(|e| e.to_string())
            })
            .interact_text()?;

        if manager.has_profile(&profile_name) {
            let overwrite = Confirm::new()
                .with_prompt(format!("Profile '{}' already exists. Overwrite?", profile_name))
                .default(false)
                .interact()?;
            if !overwrite {
                println!("{}", "Cancelled.".yellow());
                return Ok(());
            }
        }

        let description: String = Input::new()
            .with_prompt("Description (optional)")
            .default("Imported from existing git config".to_string())
            .allow_empty(true)
            .interact_text()?;

        let is_work = Confirm::new()
            .with_prompt("Is this a work profile?")
            .default(false)
            .interact()?;

        let organization = if is_work {
            Some(Input::new()
                .with_prompt("Organization")
                .interact_text()?)
        } else {
            None
        };

        let mut profile = GitProfile::new(profile_name.clone(), user_name, user_email);
        if !description.is_empty() {
            profile.description = Some(description);
        }
        profile.is_work = is_work;
        profile.organization = organization;

        if let Some(ref key) = merged_config.signing_key.value {
            profile.signing_key = Some(key.clone());
            
            let setup_gpg = Confirm::new()
                .with_prompt("Configure GPG signing details?")
                .default(true)
                .interact()?;
            
            if setup_gpg {
                profile.gpg = Some(self.setup_gpg_interactive().await?);
            }
        }

        if merged_config.ssh_command.is_set() {
            let setup_ssh = Confirm::new()
                .with_prompt("Configure SSH key details?")
                .default(false)
                .interact()?;
            
            if setup_ssh {
                profile.ssh = Some(self.setup_ssh_interactive().await?);
            }
        }

        let setup_token = Confirm::new()
            .with_prompt("Add a Personal Access Token?")
            .default(false)
            .interact()?;

        if setup_token {
            self.setup_token_interactive(&mut profile, &manager).await?;
        }

        manager.add_profile(profile_name.clone(), profile)?;
        manager.save()?;

        println!("{} Profile '{}' saved successfully", "✓".green(), profile_name.cyan());

        let set_default = Confirm::new()
            .with_prompt("Set as default profile?")
            .default(true)
            .interact()?;

        if set_default {
            manager.set_default_profile(Some(profile_name.clone()))?;
            manager.save()?;
            println!("{} Set '{}' as default profile", "✓".green(), profile_name.cyan());
        }

        Ok(())
    }

    async fn edit_profile(&self, name: &str, config_path: &Option<PathBuf>) -> Result<()> {
        let mut manager = self.get_manager(config_path)?;

        let profile = manager.get_profile(name)
            .ok_or_else(|| anyhow::anyhow!("Profile '{}' not found", name))?
            .clone();

        println!("{}", format!("\nEditing profile: {}", name).bold());
        println!("{}", "─".repeat(40));

        let user_name: String = Input::new()
            .with_prompt("Git user name")
            .default(profile.user_name.clone())
            .interact_text()?;

        let user_email: String = Input::new()
            .with_prompt("Git user email")
            .default(profile.user_email.clone())
            .validate_with(|input: &String| {
                crate::utils::validators::validate_email(input).map_err(|e| e.to_string())
            })
            .interact_text()?;

        let mut new_profile = GitProfile::new(name.to_string(), user_name, user_email);
        new_profile.description = profile.description;
        new_profile.is_work = profile.is_work;
        new_profile.organization = profile.organization;
        new_profile.ssh = profile.ssh;
        new_profile.gpg = profile.gpg;
        new_profile.tokens = profile.tokens;
        new_profile.usage = profile.usage;

        manager.update_profile(name, new_profile)?;
        manager.save()?;

        println!("{} Profile '{}' updated", "✓".green(), name);

        Ok(())
    }

    async fn set_default(&self, name: &str, config_path: &Option<PathBuf>) -> Result<()> {
        let mut manager = self.get_manager(config_path)?;

        manager.set_default_profile(Some(name.to_string()))?;
        manager.save()?;

        println!("{} Set '{}' as default profile", "✓".green(), name.cyan());

        Ok(())
    }

    async fn set_repo(&self, name: &str, config_path: &Option<PathBuf>) -> Result<()> {
        let mut manager = self.get_manager(config_path)?;
        let repo = find_repo(std::env::current_dir()?.as_path())?;

        let repo_path = repo.path().to_string_lossy().to_string();
        
        manager.set_repo_profile(repo_path.clone(), name.to_string())?;
        
        // Get the profile and apply it to the repository
        let profile = manager.get_profile(name)
            .ok_or_else(|| anyhow::anyhow!("Profile '{}' not found", name))?;
        
        profile.apply_to_repo(repo.inner())?;
        manager.record_profile_usage(name, Some(repo_path))?;
        manager.save()?;

        println!("{} Set '{}' for current repository", "✓".green(), name.cyan());
        println!("{} Applied profile '{}' to current repository", "✓".green(), name.cyan());

        Ok(())
    }

    async fn apply_profile(&self, name: Option<&str>, global: bool, config_path: &Option<PathBuf>) -> Result<()> {
        let mut manager = self.get_manager(config_path)?;

        let profile_name = if let Some(n) = name {
            n.to_string()
        } else {
            manager.default_profile_name()
                .ok_or_else(|| anyhow::anyhow!("No default profile set"))?
                .clone()
        };

        let profile = manager.get_profile(&profile_name)
            .ok_or_else(|| anyhow::anyhow!("Profile '{}' not found", profile_name))?
            .clone();

        let repo_path = if global {
            None
        } else {
            let repo = find_repo(std::env::current_dir()?.as_path())?;
            Some(repo.path().to_string_lossy().to_string())
        };

        if global {
            profile.apply_global()?;
            println!("{} Applied profile '{}' globally", "✓".green(), profile.name.cyan());
        } else {
            let repo = find_repo(std::env::current_dir()?.as_path())?;
            profile.apply_to_repo(repo.inner())?;
            println!("{} Applied profile '{}' to current repository", "✓".green(), profile.name.cyan());
        }

        manager.record_profile_usage(&profile_name, repo_path)?;
        manager.save()?;

        Ok(())
    }

    async fn switch_profile(&self, config_path: &Option<PathBuf>) -> Result<()> {
        let mut manager = self.get_manager(config_path)?;
        
        let profiles: Vec<String> = manager.list_profiles()
            .into_iter()
            .map(|s| s.to_string())
            .collect();

        if profiles.is_empty() {
            bail!("No profiles configured");
        }

        let default = manager.default_profile_name().map(|s| s.as_str());
        let default_idx = default
            .and_then(|d| profiles.iter().position(|p| p == d))
            .unwrap_or(0);

        let selection = Select::new()
            .with_prompt("Select profile to switch to")
            .items(&profiles)
            .default(default_idx)
            .interact()?;

        let selected = &profiles[selection];
        
        manager.set_default_profile(Some(selected.clone()))?;
        manager.save()?;

        println!("{} Switched to profile '{}'", "✓".green(), selected.cyan());

        if find_repo(".").is_ok() {
            let apply = Confirm::new()
                .with_prompt("Apply to current repository?")
                .default(true)
                .interact()?;

            if apply {
                self.apply_profile(Some(selected), false, config_path).await?;
            }
        }

        Ok(())
    }

    async fn copy_profile(&self, from: &str, to: &str, config_path: &Option<PathBuf>) -> Result<()> {
        let mut manager = self.get_manager(config_path)?;

        let source = manager.get_profile(from)
            .ok_or_else(|| anyhow::anyhow!("Profile '{}' not found", from))?
            .clone();

        validate_profile_name(to)?;

        let mut new_profile = source.clone();
        new_profile.name = to.to_string();
        new_profile.usage = Default::default();

        manager.add_profile(to.to_string(), new_profile)?;
        manager.save()?;

        println!("{} Copied profile '{}' to '{}'", "✓".green(), from, to.cyan());

        Ok(())
    }

    async fn handle_token_command(&self, cmd: &TokenSubcommand, config_path: &Option<PathBuf>) -> Result<()> {
        match cmd {
            TokenSubcommand::Add { profile, service } => self.add_token(profile, service, config_path).await,
            TokenSubcommand::Remove { profile, service } => self.remove_token(profile, service, config_path).await,
            TokenSubcommand::List { profile } => self.list_tokens(profile, config_path).await,
        }
    }

    async fn add_token(&self, profile_name: &str, service: &str, config_path: &Option<PathBuf>) -> Result<()> {
        let mut manager = self.get_manager(config_path)?;

        if !manager.has_profile(profile_name) {
            bail!("Profile '{}' not found", profile_name);
        }

        if !manager.keyring().is_available() {
            bail!("Keyring is not available. Cannot store PAT securely. Please ensure your system keyring is accessible.");
        }

        println!("{}", format!("\nAdd token to profile '{}'", profile_name).bold());
        println!("{}", "─".repeat(40));

        let token_value: String = Input::new()
            .with_prompt(format!("Token for {}", service))
            .interact_text()?;

        let token_type_options = vec!["Personal", "OAuth", "Deploy", "App"];
        let selection = Select::new()
            .with_prompt("Token type")
            .items(&token_type_options)
            .default(0)
            .interact()?;

        let token_type = match selection {
            0 => TokenType::Personal,
            1 => TokenType::OAuth,
            2 => TokenType::Deploy,
            3 => TokenType::App,
            _ => TokenType::Personal,
        };

        let description: String = Input::new()
            .with_prompt("Description (optional)")
            .allow_empty(true)
            .interact_text()?;

        let mut token = TokenConfig::new(token_type);
        if !description.is_empty() {
            token.description = Some(description);
        }

        manager.store_pat_for_profile(profile_name, service, &token_value)?;
        
        manager.add_token_to_profile(profile_name, service.to_string(), token)?;
        manager.save()?;

        println!("{} Token for '{}' added to profile '{}' (stored securely in keyring)", "✓".green(), service.cyan(), profile_name);

        Ok(())
    }

    async fn remove_token(&self, profile_name: &str, service: &str, config_path: &Option<PathBuf>) -> Result<()> {
        let mut manager = self.get_manager(config_path)?;

        if !manager.has_profile(profile_name) {
            bail!("Profile '{}' not found", profile_name);
        }

        let confirm = Confirm::new()
            .with_prompt(format!("Remove token '{}' from profile '{}'?", service, profile_name))
            .default(false)
            .interact()?;

        if !confirm {
            println!("{}", "Cancelled.".yellow());
            return Ok(());
        }

        manager.remove_token_from_profile(profile_name, service)?;
        manager.save()?;

        println!("{} Token '{}' removed from profile '{}' (deleted from keyring)", "✓".green(), service, profile_name);

        Ok(())
    }

    async fn list_tokens(&self, profile_name: &str, config_path: &Option<PathBuf>) -> Result<()> {
        let manager = self.get_manager(config_path)?;

        let profile = manager.get_profile(profile_name)
            .ok_or_else(|| anyhow::anyhow!("Profile '{}' not found", profile_name))?;

        if profile.tokens.is_empty() {
            println!("{} No tokens configured for profile '{}'", "ℹ".yellow(), profile_name);
            return Ok(());
        }

        println!("{}", format!("\nTokens for profile '{}':", profile_name).bold());
        println!("{}", "─".repeat(40));

        for (service, token) in &profile.tokens {
            let has_token = manager.has_pat_for_profile(profile_name, service);
            let status = if has_token {
                format!("[{}]", "stored".green())
            } else {
                format!("[{}]", "not stored".yellow())
            };
            
            println!("{} {} ({})", service.cyan().bold(), status, token.token_type);
            if let Some(ref desc) = token.description {
                println!("  {}", desc);
            }
            if let Some(ref last_used) = token.last_used {
                println!("  Last used: {}", last_used);
            }
        }

        Ok(())
    }

    async fn check_profile(&self, name: Option<&str>, config_path: &Option<PathBuf>) -> Result<()> {
        let manager = self.get_manager(config_path)?;

        let profile_name = if let Some(n) = name {
            n.to_string()
        } else {
            manager.default_profile_name()
                .ok_or_else(|| anyhow::anyhow!("No default profile set"))?
                .clone()
        };

        let repo = find_repo(std::env::current_dir()?.as_path())?;
        let comparison = manager.check_profile_config(&profile_name, repo.inner())?;

        println!("{}", format!("\nChecking profile '{}' against git configuration", profile_name).bold());
        println!("{}", "─".repeat(60));

        if comparison.matches {
            println!("{} Profile configuration matches git settings", "✓".green().bold());
        } else {
            println!("{} Profile configuration differs from git settings", "✗".red().bold());
            println!("\n{}", "Differences:".bold());
            
            for diff in &comparison.differences {
                println!("\n  {}:", diff.key.cyan());
                println!("    Profile: {}", diff.profile_value.green());
                println!("    Git:     {}", diff.git_value.yellow());
            }
        }

        Ok(())
    }

    async fn show_stats(&self, name: Option<&str>, config_path: &Option<PathBuf>) -> Result<()> {
        let manager = self.get_manager(config_path)?;

        if let Some(n) = name {
            let profile = manager.get_profile(n)
                .ok_or_else(|| anyhow::anyhow!("Profile '{}' not found", n))?;

            self.show_single_profile_stats(profile);
        } else {
            let profiles = manager.list_profiles();
            
            if profiles.is_empty() {
                println!("{}", "No profiles configured.".yellow());
                return Ok(());
            }

            println!("{}", "\nProfile Usage Statistics:".bold());
            println!("{}", "─".repeat(60));

            for profile_name in profiles {
                if let Some(profile) = manager.get_profile(profile_name) {
                    self.show_single_profile_stats(profile);
                    println!();
                }
            }
        }

        Ok(())
    }

    fn show_single_profile_stats(&self, profile: &GitProfile) {
        println!("{}", format!("\n{}", profile.name).bold());
        println!("  Total uses: {}", profile.usage.total_uses);
        
        if let Some(ref last_used) = profile.usage.last_used {
            println!("  Last used: {}", last_used);
        }

        if !profile.usage.repo_usage.is_empty() {
            println!("  Repositories:");
            for (repo, count) in &profile.usage.repo_usage {
                println!("    {} ({} uses)", repo, count);
            }
        }
    }

    async fn setup_ssh_interactive(&self) -> Result<SshConfig> {
        use std::path::PathBuf;

        let ssh_dir = dirs::home_dir()
            .map(|h| h.join(".ssh"))
            .unwrap_or_else(|| PathBuf::from("~/.ssh"));

        let key_path: String = Input::new()
            .with_prompt("SSH private key path")
            .default(ssh_dir.join("id_rsa").display().to_string())
            .interact_text()?;

        Ok(SshConfig {
            private_key_path: Some(PathBuf::from(key_path)),
            public_key_path: None,
            passphrase: None,
            agent_forwarding: false,
            ssh_command: None,
            known_hosts_file: None,
        })
    }

    async fn setup_gpg_interactive(&self) -> Result<GpgConfig> {
        let key_id: String = Input::new()
            .with_prompt("GPG key ID")
            .interact_text()?;

        Ok(GpgConfig {
            key_id,
            program: "gpg".to_string(),
            home_dir: None,
            passphrase: None,
            use_agent: true,
        })
    }

    async fn setup_token_interactive(&self, profile: &mut GitProfile, manager: &ConfigManager) -> Result<()> {
        if !manager.keyring().is_available() {
            println!("{} Keyring is not available. Cannot store PAT securely.", "⚠".yellow());
            let continue_anyway = Confirm::new()
                .with_prompt("Continue without secure token storage?")
                .default(false)
                .interact()?;
            if !continue_anyway {
                return Ok(());
            }
        }

        let service: String = Input::new()
            .with_prompt("Service name (e.g., github, gitlab)")
            .interact_text()?;

        let token_value: String = Input::new()
            .with_prompt("Token value")
            .interact_text()?;

        let token = TokenConfig::new(TokenType::Personal);
        
        if manager.keyring().is_available() {
            manager.store_pat_for_profile(&profile.name, &service, &token_value)?;
            println!("{} Token stored securely in keyring", "✓".green());
        }
        
        profile.add_token(service, token);

        Ok(())
    }
}
