use anyhow::Result;
use clap::Parser;
use colored::Colorize;
use dialoguer::{Confirm, Input, Select};

use crate::config::{GitProfile};
use crate::config::manager::ConfigManager;
use crate::config::profile::{GpgConfig, SshConfig};
use crate::utils::validators::validate_email;

/// Initialize quicommit configuration
#[derive(Parser)]
pub struct InitCommand {
    /// Skip interactive setup
    #[arg(short, long)]
    yes: bool,

    /// Reset existing configuration
    #[arg(long)]
    reset: bool,
}

impl InitCommand {
    pub async fn execute(&self) -> Result<()> {
        println!("{}", "🚀 Initializing QuiCommit...".bold().cyan());

        let config_path = crate::config::AppConfig::default_path()?;
        
        // Check if config already exists
        if config_path.exists() && !self.reset {
            if !self.yes {
                let overwrite = Confirm::new()
                    .with_prompt("Configuration already exists. Overwrite?")
                    .default(false)
                    .interact()?;
                
                if !overwrite {
                    println!("{}", "Initialization cancelled.".yellow());
                    return Ok(());
                }
            }
        }

        let mut manager = if self.reset {
            ConfigManager::new()?
        } else {
            ConfigManager::new().or_else(|_| Ok::<_, anyhow::Error>(ConfigManager::default()))?
        };

        if self.yes {
            // Quick setup with defaults
            self.quick_setup(&mut manager).await?;
        } else {
            // Interactive setup
            self.interactive_setup(&mut manager).await?;
        }

        manager.save()?;
        
        println!("{}", "✅ QuiCommit initialized successfully!".bold().green());
        println!("\nConfig file: {}", config_path.display());
        println!("\nNext steps:");
        println!("  1. Create a profile: {}", "quicommit profile add".cyan());
        println!("  2. Configure LLM: {}", "quicommit config set-llm".cyan());
        println!("  3. Start committing: {}", "quicommit commit".cyan());

        Ok(())
    }

    async fn quick_setup(&self, manager: &mut ConfigManager) -> Result<()> {
        // Try to get git user info
        let git_config = git2::Config::open_default()?;
        
        let user_name = git_config.get_string("user.name").unwrap_or_else(|_| "User".to_string());
        let user_email = git_config.get_string("user.email").unwrap_or_else(|_| "user@example.com".to_string());

        let profile = GitProfile::new(
            "default".to_string(),
            user_name,
            user_email,
        );

        manager.add_profile("default".to_string(), profile)?;
        manager.set_default_profile(Some("default".to_string()))?;

        // Set default LLM to Ollama
        manager.set_llm_provider("ollama".to_string());

        Ok(())
    }

    async fn interactive_setup(&self, manager: &mut ConfigManager) -> Result<()> {
        println!("\n{}", "Let's set up your first profile:".bold());

        // Profile name
        let profile_name: String = Input::new()
            .with_prompt("Profile name")
            .default("personal".to_string())
            .interact_text()?;

        // User info
        let git_config = git2::Config::open_default().ok();
        
        let default_name = git_config.as_ref()
            .and_then(|c| c.get_string("user.name").ok())
            .unwrap_or_default();
        
        let default_email = git_config.as_ref()
            .and_then(|c| c.get_string("user.email").ok())
            .unwrap_or_default();

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

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

        let description: String = Input::new()
            .with_prompt("Profile 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/Company name")
                .interact_text()?)
        } else {
            None
        };

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

        let ssh_config = if setup_ssh {
            Some(self.setup_ssh_interactive().await?)
        } else {
            None
        };

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

        let gpg_config = if setup_gpg {
            Some(self.setup_gpg_interactive().await?)
        } else {
            None
        };

        // Create profile
        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;
        profile.ssh = ssh_config;
        profile.gpg = gpg_config;

        manager.add_profile(profile_name.clone(), profile)?;
        manager.set_default_profile(Some(profile_name))?;

        // LLM provider selection
        println!("\n{}", "Select your preferred LLM provider:".bold());
        let providers = vec![
            "Ollama (local)",
            "OpenAI",
            "Anthropic Claude",
            "Kimi (Moonshot AI)",
            "DeepSeek",
            "OpenRouter"
        ];
        let provider_idx = Select::new()
            .items(&providers)
            .default(0)
            .interact()?;

        let provider = match provider_idx {
            0 => "ollama",
            1 => "openai",
            2 => "anthropic",
            3 => "kimi",
            4 => "deepseek",
            5 => "openrouter",
            _ => "ollama",
        };

        manager.set_llm_provider(provider.to_string());

        // Configure API key if needed
        if provider == "openai" {
            let api_key: String = Input::new()
                .with_prompt("OpenAI API key")
                .interact_text()?;
            manager.set_openai_api_key(api_key);
        } else if provider == "anthropic" {
            let api_key: String = Input::new()
                .with_prompt("Anthropic API key")
                .interact_text()?;
            manager.set_anthropic_api_key(api_key);
        } else if provider == "kimi" {
            let api_key: String = Input::new()
                .with_prompt("Kimi API key")
                .interact_text()?;
            manager.set_kimi_api_key(api_key);
        } else if provider == "deepseek" {
            let api_key: String = Input::new()
                .with_prompt("DeepSeek API key")
                .interact_text()?;
            manager.set_deepseek_api_key(api_key);
        } else if provider == "openrouter" {
            let api_key: String = Input::new()
                .with_prompt("OpenRouter API key")
                .interact_text()?;
            manager.set_openrouter_api_key(api_key);
        }

        Ok(())
    }

    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()?;

        let has_passphrase = Confirm::new()
            .with_prompt("Does this key have a passphrase?")
            .default(false)
            .interact()?;

        let passphrase = if has_passphrase {
            Some(crate::utils::password_input("SSH key passphrase")?)
        } else {
            None
        };

        Ok(SshConfig {
            private_key_path: Some(PathBuf::from(key_path)),
            public_key_path: None,
            passphrase,
            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()?;

        let use_agent = Confirm::new()
            .with_prompt("Use GPG agent?")
            .default(true)
            .interact()?;

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