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

use crate::config::{GitProfile, Language};
use crate::config::manager::ConfigManager;
use crate::config::profile::{GpgConfig, SshConfig};
use crate::i18n::Messages;
use crate::utils::keyring::{get_supported_providers, get_default_model, provider_needs_api_key};
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, config_path: Option<PathBuf>) -> Result<()> {
        let messages = Messages::new(Language::English);
        println!("{}", messages.initializing().bold().cyan());

        let config_path = config_path.unwrap_or_else(|| {
            crate::config::AppConfig::default_path().unwrap()
        });
        
        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(());
                }
            } else {
                println!("{}", "Configuration already exists. Use --reset to overwrite.".yellow());
                return Ok(());
            }
        }

        if let Some(parent) = config_path.parent() {
            std::fs::create_dir_all(parent)
                .map_err(|e| anyhow::anyhow!("Failed to create config directory: {}", e))?;
        }

        let mut manager = ConfigManager::with_path_fresh(&config_path)?;

        if self.yes {
            self.quick_setup(&mut manager).await?;
        } else {
            self.interactive_setup(&mut manager).await?;
        }

        manager.save()?;
        
        let language = manager.get_language().unwrap_or(Language::English);
        let messages = Messages::new(language);
        
        println!("{}", messages.init_success().bold().green());
        println!("\n{}: {}", messages.config_file(), config_path.display());
        println!("\n{}:", messages.next_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<()> {
        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()))?;

        manager.set_llm_provider("ollama".to_string());

        Ok(())
    }

    async fn interactive_setup(&self, manager: &mut ConfigManager) -> Result<()> {
        let messages = Messages::new(Language::English);
        println!("\n{}", messages.setup_profile().bold());

        println!("\n{}", messages.select_output_language().bold());
        let languages = [Language::English,
            Language::Chinese,
            Language::Japanese,
            Language::Korean,
            Language::Spanish,
            Language::French,
            Language::German];
        let language_names: Vec<String> = languages.iter().map(|l| l.display_name().to_string()).collect();
        let language_idx = Select::new()
            .items(&language_names)
            .default(0)
            .interact()?;

        let selected_language = languages[language_idx];
        manager.set_output_language(selected_language.to_code().to_string());

        let messages = Messages::new(selected_language);

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

        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(messages.git_user_name())
            .default(default_name)
            .interact_text()?;

        let user_email: String = Input::new()
            .with_prompt(messages.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(messages.profile_description())
            .allow_empty(true)
            .interact_text()?;

        let is_work = Confirm::new()
            .with_prompt(messages.is_work_profile())
            .default(false)
            .interact()?;

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

        let setup_ssh = Confirm::new()
            .with_prompt(messages.configure_ssh())
            .default(false)
            .interact()?;

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

        let setup_gpg = Confirm::new()
            .with_prompt(messages.configure_gpg())
            .default(false)
            .interact()?;

        let gpg_config = if setup_gpg {
            Some(self.setup_gpg_interactive(&messages).await?)
        } 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;
        profile.ssh = ssh_config;
        profile.gpg = gpg_config;

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

        println!("\n{}", messages.select_llm_provider().bold());
        
        let provider_display_names = vec![
            "Ollama (local)",
            "OpenAI",
            "Anthropic Claude",
            "Kimi (Moonshot AI)",
            "DeepSeek",
            "OpenRouter"
        ];
        
        let provider_idx = Select::new()
            .items(&provider_display_names)
            .default(0)
            .interact()?;

        let providers = get_supported_providers();
        let provider = providers[provider_idx].to_string();

        let keyring = manager.keyring();
        let keyring_available = keyring.is_available();
        
        if !keyring_available {
            println!("\n{}", "⚠ Keyring is not available on this system.".yellow());
            println!("{}", keyring.get_status_message().yellow());
        }

        let api_key = if provider_needs_api_key(&provider) {
            let env_key = std::env::var("QUICOMMIT_API_KEY")
                .or_else(|_| std::env::var(format!("QUICOMMIT_{}_API_KEY", provider.to_uppercase())))
                .ok();
            
            if let Some(_key) = env_key {
                println!("\n{} {}", "✓".green(), "Found API key in environment variable.".green());
                None
            } else if keyring_available {
                let prompt = match provider.as_str() {
                    "openai" => messages.openai_api_key(),
                    "anthropic" => messages.anthropic_api_key(),
                    "kimi" => messages.kimi_api_key(),
                    "deepseek" => messages.deepseek_api_key(),
                    "openrouter" => messages.openrouter_api_key(),
                    _ => "API Key",
                };
                
                let key: String = Input::new()
                    .with_prompt(prompt)
                    .interact_text()?;
                Some(key)
            } else {
                println!("\n{}", "Please set the QUICOMMIT_API_KEY environment variable.".yellow());
                None
            }
        } else {
            None
        };

        let default_model = get_default_model(&provider);
        let model: String = Input::new()
            .with_prompt("Model name")
            .default(default_model.to_string())
            .interact_text()?;

        let base_url: Option<String> = if provider == "ollama" {
            let url: String = Input::new()
                .with_prompt("Ollama server URL")
                .default("http://localhost:11434".to_string())
                .interact_text()?;
            Some(url)
        } else {
            let use_custom_url = Confirm::new()
                .with_prompt("Use custom API base URL?")
                .default(false)
                .interact()?;
            
            if use_custom_url {
                let url: String = Input::new()
                    .with_prompt("Base URL")
                    .interact_text()?;
                Some(url)
            } else {
                None
            }
        };

        manager.set_llm_provider(provider.clone());
        manager.set_llm_model(model);
        manager.set_llm_base_url(base_url);

        if let Some(key) = api_key
            && provider_needs_api_key(&provider) {
                manager.set_api_key(&key)?;
                println!("\n{} {}", "✓".green(), "API key stored securely in system keyring.".green());
            }

        Ok(())
    }

    async fn setup_ssh_interactive(&self, messages: &Messages) -> 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(messages.ssh_private_key_path())
            .default(ssh_dir.join("id_rsa").display().to_string())
            .interact_text()?;

        let has_passphrase = Confirm::new()
            .with_prompt(messages.has_passphrase())
            .default(false)
            .interact()?;

        let passphrase = if has_passphrase {
            Some(crate::utils::password_input(messages.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, messages: &Messages) -> Result<GpgConfig> {
        let key_id: String = Input::new()
            .with_prompt(messages.gpg_key_id())
            .interact_text()?;

        let use_agent = Confirm::new()
            .with_prompt(messages.use_gpg_agent())
            .default(true)
            .interact()?;

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