use std::collections::HashMap;
use std::path::PathBuf;

use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};

use crate::config::{
    AgentConfig, ChannelConfig, Config, FeishuChannelConfig, GatewayConfig, ModelConfig,
    ProviderConfig, SchedulerConfig, TaggedChannelConfig, WechatChannelConfig,
};

/// Interactive configuration wizard for PicoBot
pub struct InitWizard {
    read: BufReader<tokio::io::Stdin>,
    write: tokio::io::Stdout,
    config_path: PathBuf,
}

impl InitWizard {
    pub fn new() -> Self {
        let home = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
        Self {
            read: BufReader::new(tokio::io::stdin()),
            write: tokio::io::stdout(),
            config_path: home.join(".picobot").join("config.json"),
        }
    }

    pub async fn run(&mut self, force: bool, skip_channels: bool) -> Result<(), InitError> {
        let existing = self.load_existing_config(force)?;

        self.show_welcome_message();

        // Step 1: Provider
        let providers = self.configure_provider(&existing).await?;

        // Step 2: Model
        let models = self.configure_model(&existing).await?;

        // Step 3: Agent
        let agents = self.configure_agent(&existing, &providers, &models).await?;

        // Step 4: Channels
        let channels = if !skip_channels {
            self.configure_channels(&existing).await?
        } else {
            existing.channels.clone()
        };

        let config = self.build_config(providers, models, agents, channels, &existing);

        self.save_config(&config)?;

        self.show_completion_message(&config);

        Ok(())
    }

    fn load_existing_config(&self, force: bool) -> Result<Config, InitError> {
        if self.config_path.exists() && !force {
            Config::load_default().or_else(|_| Ok(Self::empty_config()))
        } else {
            Ok(Self::empty_config())
        }
    }

    fn empty_config() -> Config {
        Config {
            providers: HashMap::new(),
            models: HashMap::new(),
            agents: HashMap::new(),
            time: crate::config::TimeConfig::default(),
            gateway: GatewayConfig::default(),
            scheduler: SchedulerConfig::default(),
            client: crate::config::ClientConfig::default(),
            channels: HashMap::new(),
            skills: crate::config::SkillsConfig::default(),
            tools: crate::config::ToolsConfig::default(),
            memory_maintenance: crate::config::MemoryMaintenanceConfig::default(),
            mcp_servers: HashMap::new(),
            image_context: crate::config::ImageContextConfig::default(),
            subagents: crate::config::SubagentsConfig::default(),
        }
    }

    fn show_welcome_message(&mut self) {
        println!();
        println!("╔══════════════════════════════════════════════════════╗");
        println!("║       PicoBot Configuration Wizard                   ║");
        println!("╚══════════════════════════════════════════════════════╝");
        println!();
        println!("This wizard will help you configure PicoBot.");
        println!("Press Enter to use default values where shown.");
        println!();
    }

    // ==================== Prompt Helpers ====================

    async fn prompt_with_default(
        &mut self,
        label: &str,
        default: &str,
    ) -> Result<String, InitError> {
        if !default.is_empty() {
            println!("{} [default: {}]: ", label, default);
        } else {
            println!("{}: ", label);
        }
        self.write.flush().await?;

        let mut line = String::new();
        let bytes_read = self.read.read_line(&mut line).await?;

        if bytes_read == 0 {
            return Err(InitError::InputError("EOF reached".to_string()));
        }

        let input = line.trim().to_string();
        Ok(if input.is_empty() { default.to_string() } else { input })
    }

    async fn prompt_required(&mut self, label: &str) -> Result<String, InitError> {
        loop {
            println!("{}: ", label);
            self.write.flush().await?;

            let mut line = String::new();
            let bytes_read = self.read.read_line(&mut line).await?;

            if bytes_read == 0 {
                return Err(InitError::InputError("EOF reached".to_string()));
            }

            let input = line.trim().to_string();
            if !input.is_empty() {
                return Ok(input);
            }
            println!("{} is required. Please enter a value.", label);
        }
    }

    async fn prompt_select(
        &mut self,
        label: &str,
        options: &[String],
        default: usize,
    ) -> Result<usize, InitError> {
        for (i, opt) in options.iter().enumerate() {
            println!("  {}. {}", i + 1, opt);
        }
        println!();

        let default_str = (default + 1).to_string();
        let input = self.prompt_with_default(label, &default_str).await?;

        let selected: usize = input.parse().map_err(|_| {
            InitError::InputError(format!("Invalid selection: {}", input))
        })?;

        if selected == 0 || selected > options.len() {
            return Err(InitError::InputError(format!(
                "Selection must be between 1 and {}",
                options.len()
            )));
        }

        Ok(selected - 1)
    }

    // ==================== Step 1: Provider ====================

    async fn configure_provider(
        &mut self,
        existing: &Config,
    ) -> Result<HashMap<String, ProviderConfig>, InitError> {
        println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
        println!("Step 1: Configure Provider (API Endpoint)");
        println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
        println!();

        let provider_names: Vec<String> = existing.providers.keys().cloned().collect();

        if !provider_names.is_empty() {
            println!("Existing providers:");
            for (i, name) in provider_names.iter().enumerate() {
                println!("  {}. {}", i + 1, name);
            }
            println!();

            println!("Options:");
            println!("  1. Add new provider");
            println!("  2. Modify existing provider");
            println!("  3. Use existing provider");
            println!("  4. Skip");
            println!();

            let choice = self
                .prompt_with_default("Select option", "1")
                .await?;

            match choice.as_str() {
                "1" => return self.add_provider(existing).await,
                "2" => return self.modify_provider(existing).await,
                "3" => {
                    println!("Keeping existing providers.");
                    return Ok(existing.providers.clone());
                }
                "4" => {
                    println!("Skipping provider configuration.");
                    return Ok(existing.providers.clone());
                }
                _ => {
                    println!("Invalid option, adding new provider.");
                    return self.add_provider(existing).await;
                }
            }
        } else {
            println!("No existing providers found.");
            println!();
            println!("Options:");
            println!("  1. Add new provider");
            println!("  2. Skip");
            println!();

            let choice = self.prompt_with_default("Select option", "1").await?;

            match choice.as_str() {
                "1" => self.add_provider(existing).await,
                "2" => {
                    println!("Skipping provider configuration.");
                    Ok(existing.providers.clone())
                }
                _ => {
                    println!("Invalid option, adding new provider.");
                    self.add_provider(existing).await
                }
            }
        }
    }

    async fn add_provider(
        &mut self,
        existing: &Config,
    ) -> Result<HashMap<String, ProviderConfig>, InitError> {
        let provider_name = self
            .prompt_with_default("Provider name", "default")
            .await?;

        println!("Provider type:");
        println!("  1. openai");
        println!("  2. anthropic");
        println!();
        let type_choice = self.prompt_with_default("Select type", "1").await?;
        let provider_type = match type_choice.as_str() {
            "1" => "openai",
            "2" => "anthropic",
            _ => "openai",
        };

        let base_url = self.prompt_required("API base URL").await?;

        println!();
        println!("API Key is required and will be stored in config.json.");
        let api_key = self.prompt_required("API Key").await?;

        let provider = ProviderConfig {
            provider_type: provider_type.to_string(),
            base_url,
            api_key,
            extra_headers: HashMap::new(),
            llm_timeout_secs: 120,
            memory_maintenance_timeout_secs: 600,
        };

        let mut providers = existing.providers.clone();
        providers.insert(provider_name.clone(), provider);

        println!();
        println!("Provider '{}' configured.", provider_name);

        Ok(providers)
    }

    async fn modify_provider(
        &mut self,
        existing: &Config,
    ) -> Result<HashMap<String, ProviderConfig>, InitError> {
        // Select which provider to modify
        let provider_names: Vec<String> = existing.providers.keys().cloned().collect();
        println!("Select provider to modify:");
        let provider_idx = self.prompt_select("", &provider_names, 0).await?;
        let selected_provider_name = &provider_names[provider_idx];
        let current_provider = existing.providers.get(selected_provider_name).unwrap();

        println!();
        println!(
            "Current config: type={}, base_url={}",
            current_provider.provider_type, current_provider.base_url
        );
        println!();

        let current_type_idx = if current_provider.provider_type == "anthropic" {
            1
        } else {
            0
        };
        let type_options = vec!["openai".to_string(), "anthropic".to_string()];
        println!("Provider type:");
        let type_idx = self.prompt_select("", &type_options, current_type_idx).await?;
        let provider_type = &type_options[type_idx];

        let base_url = self
            .prompt_with_default("API base URL", &current_provider.base_url)
            .await?;

        println!();
        println!("API Key (press Enter to keep current key):");
        let api_key = self
            .prompt_with_default("API Key", &current_provider.api_key)
            .await?;

        let provider = ProviderConfig {
            provider_type: provider_type.clone(),
            base_url,
            api_key,
            extra_headers: current_provider.extra_headers.clone(),
            llm_timeout_secs: current_provider.llm_timeout_secs,
            memory_maintenance_timeout_secs: current_provider.memory_maintenance_timeout_secs,
        };

        let mut providers = existing.providers.clone();
        providers.insert(selected_provider_name.clone(), provider);

        println!();
        println!("Provider '{}' modified.", selected_provider_name);

        Ok(providers)
    }

    // ==================== Step 2: Model ====================

    async fn configure_model(
        &mut self,
        existing: &Config,
    ) -> Result<HashMap<String, ModelConfig>, InitError> {
        println!();
        println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
        println!("Step 2: Configure Model");
        println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
        println!();

        let model_names: Vec<String> = existing.models.keys().cloned().collect();

        if !model_names.is_empty() {
            println!("Existing models:");
            for (i, name) in model_names.iter().enumerate() {
                let model = existing.models.get(name).unwrap();
                println!("  {}. {} (model_id: {})", i + 1, name, model.model_id);
            }
            println!();

            println!("Options:");
            println!("  1. Use existing model");
            println!("  2. Add new model");
            println!("  3. Skip");
            println!();

            let choice = self.prompt_with_default("Select option", "1").await?;

            match choice.as_str() {
                "1" => {
                    println!("Keeping existing models.");
                    return Ok(existing.models.clone());
                }
                "2" => return self.add_model(existing).await,
                "3" => {
                    println!("Skipping model configuration.");
                    return Ok(existing.models.clone());
                }
                _ => {
                    println!("Invalid option, keeping existing models.");
                    return Ok(existing.models.clone());
                }
            }
        } else {
            println!("No existing models found.");
            println!();
            println!("Options:");
            println!("  1. Add new model");
            println!("  2. Skip");
            println!();

            let choice = self.prompt_with_default("Select option", "1").await?;

            match choice.as_str() {
                "1" => self.add_model(existing).await,
                "2" => {
                    println!("Skipping model configuration.");
                    Ok(existing.models.clone())
                }
                _ => self.add_model(existing).await,
            }
        }
    }

    async fn add_model(
        &mut self,
        existing: &Config,
    ) -> Result<HashMap<String, ModelConfig>, InitError> {
        let model_name = self
            .prompt_with_default("Model name (reference key)", "default")
            .await?;

        let model_id = self.prompt_required("Model ID (actual identifier)").await?;

        let temperature_str = self
            .prompt_with_default("Temperature (0.0-1.0)", "0.7")
            .await?;
        let temperature: Option<f32> = temperature_str
            .parse()
            .ok()
            .filter(|v| (0.0..=1.0).contains(v));

        let max_tokens_str = self
            .prompt_with_default("Max tokens (optional)", "4096")
            .await?;
        let max_tokens: Option<u32> = max_tokens_str.parse().ok();

        let model = ModelConfig {
            model_id,
            temperature,
            max_tokens,
            context_window_tokens: Some(128000),
            extra: HashMap::new(),
        };

        let mut models = existing.models.clone();
        models.insert(model_name.clone(), model);

        println!();
        println!("Model '{}' configured.", model_name);

        Ok(models)
    }

    // ==================== Step 3: Agent ====================

    async fn configure_agent(
        &mut self,
        existing: &Config,
        providers: &HashMap<String, ProviderConfig>,
        models: &HashMap<String, ModelConfig>,
    ) -> Result<HashMap<String, AgentConfig>, InitError> {
        println!();
        println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
        println!("Step 3: Configure Agent");
        println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
        println!();

        // Check if we have providers and models to select from
        if providers.is_empty() {
            println!("Warning: No providers configured. Please configure a provider first.");
            return Ok(existing.agents.clone());
        }
        if models.is_empty() {
            println!("Warning: No models configured. Please configure a model first.");
            return Ok(existing.agents.clone());
        }

        let agent_names: Vec<String> = existing.agents.keys().cloned().collect();

        if !agent_names.is_empty() {
            println!("Existing agents:");
            for (i, name) in agent_names.iter().enumerate() {
                let agent = existing.agents.get(name).unwrap();
                println!(
                    "  {}. {} (provider: {}, model: {})",
                    i + 1,
                    name,
                    agent.provider,
                    agent.model
                );
            }
            println!();

            println!("Options:");
            println!("  1. Add new agent");
            println!("  2. Modify existing agent");
            println!("  3. Use existing agent");
            println!("  4. Skip");
            println!();

            let choice = self.prompt_with_default("Select option", "1").await?;

            match choice.as_str() {
                "1" => return self.add_agent(existing, providers, models).await,
                "2" => return self.modify_agent(existing, providers, models).await,
                "3" => {
                    println!("Keeping existing agents.");
                    return Ok(existing.agents.clone());
                }
                "4" => {
                    println!("Skipping agent configuration.");
                    return Ok(existing.agents.clone());
                }
                _ => {
                    println!("Invalid option, adding new agent.");
                    return self.add_agent(existing, providers, models).await;
                }
            }
        } else {
            println!("No existing agents found.");
            println!();
            println!("Options:");
            println!("  1. Add new agent");
            println!("  2. Skip");
            println!();

            let choice = self.prompt_with_default("Select option", "1").await?;

            match choice.as_str() {
                "1" => self.add_agent(existing, providers, models).await,
                "2" => {
                    println!("Skipping agent configuration.");
                    Ok(existing.agents.clone())
                }
                _ => self.add_agent(existing, providers, models).await,
            }
        }
    }

    async fn add_agent(
        &mut self,
        existing: &Config,
        providers: &HashMap<String, ProviderConfig>,
        models: &HashMap<String, ModelConfig>,
    ) -> Result<HashMap<String, AgentConfig>, InitError> {
        let agent_name = self
            .prompt_with_default("Agent name", "default")
            .await?;

        // Select provider
        let provider_names: Vec<String> = providers.keys().cloned().collect();
        println!("Select provider:");
        let provider_idx = self.prompt_select("", &provider_names, 0).await?;
        let selected_provider = &provider_names[provider_idx];

        // Select model (independently)
        let model_names: Vec<String> = models.keys().cloned().collect();
        println!();
        println!("Select model:");
        let model_idx = self.prompt_select("", &model_names, 0).await?;
        let selected_model = &model_names[model_idx];

        let agent = AgentConfig {
            provider: selected_provider.clone(),
            model: selected_model.clone(),
            max_tool_iterations: 100,
            tool_result_max_chars: 100_000,
            context_tool_result_trim_chars: 2000,
        };

        let mut agents = existing.agents.clone();
        agents.insert(agent_name.clone(), agent);

        println!();
        println!(
            "Agent '{}' configured (provider: {}, model: {}).",
            agent_name, selected_provider, selected_model
        );

        Ok(agents)
    }

    async fn modify_agent(
        &mut self,
        existing: &Config,
        providers: &HashMap<String, ProviderConfig>,
        models: &HashMap<String, ModelConfig>,
    ) -> Result<HashMap<String, AgentConfig>, InitError> {
        // Select which agent to modify
        let agent_names: Vec<String> = existing.agents.keys().cloned().collect();
        println!("Select agent to modify:");
        let agent_idx = self.prompt_select("", &agent_names, 0).await?;
        let selected_agent_name = &agent_names[agent_idx];
        let current_agent = existing.agents.get(selected_agent_name).unwrap();

        println!();
        println!(
            "Current config: provider={}, model={}",
            current_agent.provider, current_agent.model
        );
        println!();

        // Select new provider
        let provider_names: Vec<String> = providers.keys().cloned().collect();
        let current_provider_idx = provider_names
            .iter()
            .position(|p| p == &current_agent.provider)
            .unwrap_or(0);
        println!("Select provider:");
        let provider_idx = self.prompt_select("", &provider_names, current_provider_idx).await?;
        let selected_provider = &provider_names[provider_idx];

        // Select new model
        let model_names: Vec<String> = models.keys().cloned().collect();
        let current_model_idx = model_names
            .iter()
            .position(|m| m == &current_agent.model)
            .unwrap_or(0);
        println!();
        println!("Select model:");
        let model_idx = self.prompt_select("", &model_names, current_model_idx).await?;
        let selected_model = &model_names[model_idx];

        let agent = AgentConfig {
            provider: selected_provider.clone(),
            model: selected_model.clone(),
            max_tool_iterations: current_agent.max_tool_iterations,
            tool_result_max_chars: current_agent.tool_result_max_chars,
            context_tool_result_trim_chars: current_agent.context_tool_result_trim_chars,
        };

        let mut agents = existing.agents.clone();
        agents.insert(selected_agent_name.clone(), agent);

        println!();
        println!(
            "Agent '{}' modified (provider: {}, model: {}).",
            selected_agent_name, selected_provider, selected_model
        );

        Ok(agents)
    }

    // ==================== Step 4: Channels ====================

    async fn configure_channels(
        &mut self,
        existing: &Config,
    ) -> Result<HashMap<String, ChannelConfig>, InitError> {
        println!();
        println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
        println!("Step 4: Configure Channels");
        println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
        println!();

        // Show existing channels
        if !existing.channels.is_empty() {
            println!("Existing channels:");
            for (name, config) in &existing.channels {
                let status = if config.enabled() { "enabled" } else { "disabled" };
                println!("  - {} ({})", name, status);
            }
            println!();
        }

        let mut channels = existing.channels.clone();

        // Loop for configuring multiple channels
        loop {
            println!("Options:");
            println!("  1. Add Feishu channel");
            println!("  2. Add WeChat channel");
            println!("  3. Skip / Done");
            println!();

            let choice = self.prompt_with_default("Select option", "3").await?;

            match choice.as_str() {
                "1" => {
                    let channel_config = self.configure_feishu_channel(&channels).await?;
                    for (name, config) in channel_config {
                        channels.insert(name, config);
                    }
                }
                "2" => {
                    let channel_config = self.configure_wechat_channel(&channels).await?;
                    for (name, config) in channel_config {
                        channels.insert(name, config);
                    }
                }
                "3" => break,
                _ => {
                    println!("Invalid selection.");
                    continue;
                }
            }
        }

        Ok(channels)
    }

    async fn configure_feishu_channel(
        &mut self,
        existing: &HashMap<String, ChannelConfig>,
    ) -> Result<HashMap<String, ChannelConfig>, InitError> {
        println!();
        println!("Configuring Feishu channel...");
        println!();

        let channel_name = self
            .prompt_with_default("Channel name", "feishu")
            .await?;

        let _existing_config = existing.get(&channel_name).and_then(|c| c.as_feishu());

        let app_id = self.prompt_required("Feishu App ID").await?;
        let app_secret = self.prompt_required("Feishu App Secret").await?;

        let config = ChannelConfig::Tagged(TaggedChannelConfig::Feishu(FeishuChannelConfig {
            enabled: true,
            app_id,
            app_secret,
            allow_from: vec!["*".to_string()],
            agent: "default".to_string(),
            media_dir: Self::default_feishu_media_dir(),
            reaction_emoji: "Typing".to_string(),
            max_message_chars: 20000,
            reply_context_max_chars: 20000,
        }));

        let mut result = HashMap::new();
        result.insert(channel_name.clone(), config);

        println!();
        println!("Feishu channel '{}' configured.", channel_name);

        Ok(result)
    }

    async fn configure_wechat_channel(
        &mut self,
        _existing: &HashMap<String, ChannelConfig>,
    ) -> Result<HashMap<String, ChannelConfig>, InitError> {
        println!();
        println!("Configuring WeChat channel...");
        println!();
        println!("WeChat login requires scanning a QR code.");
        println!("The QR code URL will be displayed after configuration.");
        println!();

        // Use default values directly
        let channel_name = "wechat";
        let base_url = "https://ilinkai.weixin.qq.com";
        let cred_path = Self::default_wechat_cred_path();
        let force_login = false;

        let config = ChannelConfig::Tagged(TaggedChannelConfig::Wechat(WechatChannelConfig {
            enabled: true,
            allow_from: vec!["*".to_string()],
            agent: "default".to_string(),
            base_url: base_url.to_string(),
            cred_path,
            force_login,
        }));

        let mut result = HashMap::new();
        result.insert(channel_name.to_string(), config);

        println!();
        println!("WeChat channel '{}' configured.", channel_name);

        // Auto login after configuration
        println!();
        println!("Starting WeChat login...");

        self.do_wechat_login(base_url, &Self::default_wechat_cred_path()).await?;

        println!();
        println!("WeChat login successful! Credentials saved.");

        Ok(result)
    }

    async fn do_wechat_login(&mut self, base_url: &str, cred_path: &str) -> Result<(), InitError> {
        use wechatbot::{BotOptions, WeChatBot};

        let bot = WeChatBot::new(BotOptions {
            base_url: Some(base_url.to_string()),
            cred_path: Some(cred_path.to_string()),
            on_qr_url: Some(Box::new(|url| {
                println!();
                println!("┌──────────────────────────────────────────────────────┐");
                println!("│ WeChat QR Code                                        │");
                println!("└──────────────────────────────────────────────────────┘");
                println!();
                println!("Scan this URL in WeChat:");
                println!("{}", url);
                println!();
                println!("Waiting for confirmation...");
            })),
            on_error: Some(Box::new(|error| {
                eprintln!("WeChat login error: {}", error);
            })),
        });

        let creds = bot.login(true).await.map_err(|e| {
            InitError::WeChatError(format!("WeChat login failed: {}", e))
        })?;

        println!();
        println!(
            "Logged in as: {} (account: {})",
            creds.user_id, creds.account_id
        );

        Ok(())
    }

    // ==================== Build & Save ====================

    fn build_config(
        &self,
        providers: HashMap<String, ProviderConfig>,
        models: HashMap<String, ModelConfig>,
        agents: HashMap<String, AgentConfig>,
        channels: HashMap<String, ChannelConfig>,
        existing: &Config,
    ) -> Config {
        Config {
            providers,
            models,
            agents,
            channels,
            time: existing.time.clone(),
            gateway: existing.gateway.clone(),
            scheduler: existing.scheduler.clone(),
            client: existing.client.clone(),
            skills: existing.skills.clone(),
            tools: existing.tools.clone(),
            memory_maintenance: existing.memory_maintenance.clone(),
            mcp_servers: existing.mcp_servers.clone(),
            image_context: existing.image_context.clone(),
            subagents: existing.subagents.clone(),
        }
    }

    fn save_config(&self, config: &Config) -> Result<(), InitError> {
        let dir = self
            .config_path
            .parent()
            .ok_or_else(|| InitError::IoError("Invalid config path".to_string()))?;
        std::fs::create_dir_all(dir)
            .map_err(|e| InitError::IoError(format!("Failed to create directory: {}", e)))?;

        let content = serde_json::to_string_pretty(config)
            .map_err(|e| InitError::SerializeError(e.to_string()))?;

        std::fs::write(&self.config_path, content)
            .map_err(|e| InitError::IoError(format!("Failed to write config: {}", e)))?;

        Ok(())
    }

    fn show_completion_message(&mut self, config: &Config) {
        println!();
        println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
        println!("Configuration complete!");
        println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
        println!();
        println!("Config saved to: {}", self.config_path.display());
        println!();

        println!("Summary:");
        println!("  Providers: {}", config.providers.len());
        println!("  Models: {}", config.models.len());
        println!("  Agents: {}", config.agents.len());
        println!("  Channels: {}", config.channels.len());
        println!();

        println!("Next steps:");
        println!("  1. Start the gateway: picobot gateway");
        println!("  2. Connect with CLI:   picobot agent");
        println!();
        println!("For more options, run: picobot --help");
        println!();
    }

    fn default_feishu_media_dir() -> String {
        let home = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
        home.join(".picobot/media/feishu")
            .to_string_lossy()
            .to_string()
    }

    fn default_wechat_cred_path() -> String {
        let home = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
        home.join(".picobot/wechat/credentials.json")
            .to_string_lossy()
            .to_string()
    }
}

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

#[derive(Debug)]
pub enum InitError {
    IoError(String),
    SerializeError(String),
    InputError(String),
    WeChatError(String),
}

impl std::fmt::Display for InitError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            InitError::IoError(msg) => write!(f, "IO error: {}", msg),
            InitError::SerializeError(msg) => write!(f, "Serialization error: {}", msg),
            InitError::InputError(msg) => write!(f, "Input error: {}", msg),
            InitError::WeChatError(msg) => write!(f, "WeChat error: {}", msg),
        }
    }
}

impl std::error::Error for InitError {}

impl From<std::io::Error> for InitError {
    fn from(e: std::io::Error) -> Self {
        InitError::IoError(e.to_string())
    }
}