//! Simple Configuration Wizard for Rustelo Template
//!
//! This binary creates an interactive configuration wizard that generates config.toml
//! and updates Cargo.toml features based on user preferences, using only Rust std library.

use std::collections::HashMap;
use std::fs;
use std::io::{self, Write};
use std::path::Path;

#[derive(Debug, Clone)]
pub struct FeatureInfo {
    pub name: String,
    pub description: String,
    pub dependencies: Vec<String>,
    pub cargo_features: Vec<String>,
}

#[derive(Debug, Default)]
pub struct WizardConfig {
    pub selected_features: Vec<String>,
    pub server: ServerConfig,
    pub database: Option<DatabaseConfig>,
    pub auth: Option<AuthConfig>,
    pub oauth: Option<OAuthConfig>,
    pub email: Option<EmailConfig>,
    pub security: SecurityConfig,
    pub monitoring: Option<MonitoringConfig>,
    pub ssl: Option<SslConfig>,
    pub cache: Option<CacheConfig>,
}

#[derive(Debug, Default)]
pub struct ServerConfig {
    pub host: String,
    pub port: u16,
    pub environment: String,
    pub workers: u32,
    pub protocol: String,
}

#[derive(Debug, Default)]
pub struct DatabaseConfig {
    pub url: String,
    pub max_connections: u32,
    pub enable_logging: bool,
}

#[derive(Debug, Default)]
pub struct AuthConfig {
    pub jwt_secret: String,
    pub session_timeout: u32,
    pub max_login_attempts: u32,
    pub require_email_verification: bool,
}

#[derive(Debug, Default)]
pub struct OAuthConfig {
    pub enabled: bool,
    pub google: Option<OAuthProvider>,
    pub github: Option<OAuthProvider>,
    pub microsoft: Option<OAuthProvider>,
}

#[derive(Debug, Default)]
pub struct OAuthProvider {
    pub client_id: String,
    pub client_secret: String,
    pub redirect_uri: String,
}

#[derive(Debug, Default)]
pub struct EmailConfig {
    pub smtp_host: String,
    pub smtp_port: u16,
    pub smtp_username: String,
    pub smtp_password: String,
    pub from_email: String,
    pub from_name: String,
}

#[derive(Debug, Default)]
pub struct SecurityConfig {
    pub enable_csrf: bool,
    pub rate_limit_requests: u32,
    pub bcrypt_cost: u32,
}

#[derive(Debug, Default)]
pub struct MonitoringConfig {
    pub enabled: bool,
    pub metrics_port: u16,
    pub prometheus_enabled: bool,
}

#[derive(Debug, Default)]
pub struct SslConfig {
    pub force_https: bool,
    pub cert_path: String,
    pub key_path: String,
}

#[derive(Debug, Default)]
pub struct CacheConfig {
    pub enabled: bool,
    pub cache_type: String,
    pub default_ttl: u32,
}

pub struct ConfigWizard {
    features: HashMap<String, FeatureInfo>,
}

impl ConfigWizard {
    pub fn new() -> Self {
        let mut features = HashMap::new();

        // Define available features
        features.insert(
            "auth".to_string(),
            FeatureInfo {
                name: "auth".to_string(),
                description: "Authentication and authorization system".to_string(),
                dependencies: vec!["crypto".to_string()],
                cargo_features: vec!["auth".to_string()],
            },
        );

        features.insert(
            "tls".to_string(),
            FeatureInfo {
                name: "tls".to_string(),
                description: "TLS/SSL support for secure connections".to_string(),
                dependencies: vec![],
                cargo_features: vec!["tls".to_string()],
            },
        );

        features.insert(
            "rbac".to_string(),
            FeatureInfo {
                name: "rbac".to_string(),
                description: "Role-based access control".to_string(),
                dependencies: vec!["auth".to_string()],
                cargo_features: vec!["rbac".to_string()],
            },
        );

        features.insert(
            "crypto".to_string(),
            FeatureInfo {
                name: "crypto".to_string(),
                description: "Cryptographic utilities and encryption".to_string(),
                dependencies: vec![],
                cargo_features: vec!["crypto".to_string()],
            },
        );

        features.insert(
            "content-db".to_string(),
            FeatureInfo {
                name: "content-db".to_string(),
                description: "Content management and database features".to_string(),
                dependencies: vec![],
                cargo_features: vec!["content-db".to_string()],
            },
        );

        features.insert(
            "email".to_string(),
            FeatureInfo {
                name: "email".to_string(),
                description: "Email sending capabilities".to_string(),
                dependencies: vec![],
                cargo_features: vec!["email".to_string()],
            },
        );

        features.insert(
            "metrics".to_string(),
            FeatureInfo {
                name: "metrics".to_string(),
                description: "Prometheus metrics collection".to_string(),
                dependencies: vec![],
                cargo_features: vec!["metrics".to_string()],
            },
        );

        features.insert(
            "examples".to_string(),
            FeatureInfo {
                name: "examples".to_string(),
                description: "Include example code and documentation".to_string(),
                dependencies: vec![],
                cargo_features: vec!["examples".to_string()],
            },
        );

        features.insert("production".to_string(), FeatureInfo {
            name: "production".to_string(),
            description: "Production-ready configuration (includes: auth, content-db, crypto, email, metrics, tls)".to_string(),
            dependencies: vec!["auth".to_string(), "content-db".to_string(), "crypto".to_string(), "email".to_string(), "metrics".to_string(), "tls".to_string()],
            cargo_features: vec!["production".to_string()],
        });

        Self { features }
    }

    pub fn run_wizard(&self) -> Result<WizardConfig, Box<dyn std::error::Error>> {
        println!("=== Rustelo Configuration Wizard ===");
        println!("This wizard will help you configure your Rustelo application.\n");

        let mut config = WizardConfig::default();

        // Feature selection
        println!("\n--- Feature Selection ---");
        println!("Select the features you want to enable:\n");

        let mut selected_features = Vec::new();
        for (name, info) in &self.features {
            if self.ask_yes_no(&format!("Enable {}? ({})", name, info.description))? {
                selected_features.push(name.clone());
            }
        }

        // Handle dependencies
        selected_features = self.resolve_dependencies(selected_features);
        config.selected_features = selected_features.clone();

        // Server configuration
        println!("\n--- Server Configuration ---");
        config.server.host = self.ask_string("Server host", "127.0.0.1")?;
        config.server.port = self.ask_number("Server port", 3030)? as u16;
        config.server.environment = self.ask_string("Environment (dev/prod/test)", "dev")?;
        config.server.workers = self.ask_number("Number of workers", 4)? as u32;
        config.server.protocol = "http".to_string();

        // Database configuration
        if selected_features.contains(&"content-db".to_string()) {
            println!("\n--- Database Configuration ---");
            config.database = Some(DatabaseConfig {
                url: self.ask_string("Database URL", "sqlite:rustelo.db")?,
                max_connections: self.ask_number("Max database connections", 10)? as u32,
                enable_logging: self.ask_yes_no("Enable database query logging")?,
            });
        }

        // Authentication configuration
        if selected_features.contains(&"auth".to_string()) {
            println!("\n--- Authentication Configuration ---");
            config.auth = Some(AuthConfig {
                jwt_secret: self.ask_string("JWT secret (leave empty for auto-generation)", "")?,
                session_timeout: self.ask_number("Session timeout (minutes)", 60)? as u32,
                max_login_attempts: self.ask_number("Max login attempts", 5)? as u32,
                require_email_verification: self.ask_yes_no("Require email verification")?,
            });

            // OAuth configuration
            if self.ask_yes_no("Enable OAuth providers?")? {
                let mut oauth_config = OAuthConfig {
                    enabled: true,
                    ..Default::default()
                };

                if self.ask_yes_no("Enable Google OAuth?")? {
                    oauth_config.google = Some(OAuthProvider {
                        client_id: self.ask_string("Google OAuth Client ID", "")?,
                        client_secret: self.ask_string("Google OAuth Client Secret", "")?,
                        redirect_uri: self.ask_string(
                            "Google OAuth Redirect URI",
                            "http://localhost:3030/auth/google/callback",
                        )?,
                    });
                }

                if self.ask_yes_no("Enable GitHub OAuth?")? {
                    oauth_config.github = Some(OAuthProvider {
                        client_id: self.ask_string("GitHub OAuth Client ID", "")?,
                        client_secret: self.ask_string("GitHub OAuth Client Secret", "")?,
                        redirect_uri: self.ask_string(
                            "GitHub OAuth Redirect URI",
                            "http://localhost:3030/auth/github/callback",
                        )?,
                    });
                }

                if self.ask_yes_no("Enable Microsoft OAuth?")? {
                    oauth_config.microsoft = Some(OAuthProvider {
                        client_id: self.ask_string("Microsoft OAuth Client ID", "")?,
                        client_secret: self.ask_string("Microsoft OAuth Client Secret", "")?,
                        redirect_uri: self.ask_string(
                            "Microsoft OAuth Redirect URI",
                            "http://localhost:3030/auth/microsoft/callback",
                        )?,
                    });
                }

                config.oauth = Some(oauth_config);
            }
        }

        // Email configuration
        if selected_features.contains(&"email".to_string()) {
            println!("\n--- Email Configuration ---");
            config.email = Some(EmailConfig {
                smtp_host: self.ask_string("SMTP host", "localhost")?,
                smtp_port: self.ask_number("SMTP port", 587)? as u16,
                smtp_username: self.ask_string("SMTP username", "")?,
                smtp_password: self.ask_string("SMTP password", "")?,
                from_email: self.ask_string("From email address", "noreply@localhost")?,
                from_name: self.ask_string("From name", "Rustelo App")?,
            });
        }

        // Security configuration
        println!("\n--- Security Configuration ---");
        config.security = SecurityConfig {
            enable_csrf: self.ask_yes_no("Enable CSRF protection")?,
            rate_limit_requests: self.ask_number("Rate limit requests per minute", 100)? as u32,
            bcrypt_cost: self.ask_number("BCrypt cost (4-31)", 12)? as u32,
        };

        // SSL/TLS configuration
        if selected_features.contains(&"tls".to_string()) {
            println!("\n--- SSL/TLS Configuration ---");
            config.ssl = Some(SslConfig {
                force_https: self.ask_yes_no("Force HTTPS")?,
                cert_path: self.ask_string("SSL certificate path", "")?,
                key_path: self.ask_string("SSL private key path", "")?,
            });
        }

        // Monitoring configuration
        if selected_features.contains(&"metrics".to_string()) {
            println!("\n--- Monitoring Configuration ---");
            if self.ask_yes_no("Enable monitoring")? {
                config.monitoring = Some(MonitoringConfig {
                    enabled: true,
                    metrics_port: self.ask_number("Metrics port", 9090)? as u16,
                    prometheus_enabled: self.ask_yes_no("Enable Prometheus metrics")?,
                });
            }
        }

        // Cache configuration
        println!("\n--- Cache Configuration ---");
        if self.ask_yes_no("Enable caching")? {
            config.cache = Some(CacheConfig {
                enabled: true,
                cache_type: self.ask_string("Cache type (memory/redis)", "memory")?,
                default_ttl: self.ask_number("Default TTL (seconds)", 3600)? as u32,
            });
        }

        Ok(config)
    }

    fn resolve_dependencies(&self, selected: Vec<String>) -> Vec<String> {
        let mut resolved = Vec::new();
        let mut to_process = selected.clone();

        while let Some(feature) = to_process.pop() {
            if resolved.contains(&feature) {
                continue;
            }

            resolved.push(feature.clone());

            if let Some(info) = self.features.get(&feature) {
                for dep in &info.dependencies {
                    if !resolved.contains(dep) && !to_process.contains(dep) {
                        to_process.push(dep.clone());
                    }
                }
            }
        }

        resolved.sort();
        resolved.dedup();
        resolved
    }

    fn ask_yes_no(&self, question: &str) -> Result<bool, Box<dyn std::error::Error>> {
        loop {
            print!("{} (y/n): ", question);
            io::stdout().flush()?;
            let mut input = String::new();
            io::stdin().read_line(&mut input)?;
            match input.trim().to_lowercase().as_str() {
                "y" | "yes" => return Ok(true),
                "n" | "no" => return Ok(false),
                _ => println!("Please enter 'y' or 'n'"),
            }
        }
    }

    fn ask_string(
        &self,
        question: &str,
        default: &str,
    ) -> Result<String, Box<dyn std::error::Error>> {
        if !default.is_empty() {
            print!("{} [{}]: ", question, default);
        } else {
            print!("{}: ", question);
        }
        io::stdout().flush()?;
        let mut input = String::new();
        io::stdin().read_line(&mut input)?;
        let input = input.trim();
        Ok(if input.is_empty() {
            default.to_string()
        } else {
            input.to_string()
        })
    }

    fn ask_number(&self, question: &str, default: i32) -> Result<i32, Box<dyn std::error::Error>> {
        loop {
            print!("{} [{}]: ", question, default);
            io::stdout().flush()?;
            let mut input = String::new();
            io::stdin().read_line(&mut input)?;
            let input = input.trim();
            if input.is_empty() {
                return Ok(default);
            }
            match input.parse::<i32>() {
                Ok(num) => return Ok(num),
                Err(_) => println!("Please enter a valid number"),
            }
        }
    }

    pub fn generate_config_toml(&self, config: &WizardConfig) -> String {
        let mut toml = String::new();

        toml.push_str("# Rustelo Configuration File\n");
        toml.push_str("# Generated by Configuration Wizard\n\n");
        toml.push_str("root_path = \".\"\n\n");

        // Features section
        toml.push_str("[features]\n");
        for feature in &config.selected_features {
            toml.push_str(&format!("{} = true\n", feature));
        }
        toml.push_str("\n");

        // Server section
        toml.push_str("[server]\n");
        toml.push_str(&format!("protocol = \"{}\"\n", config.server.protocol));
        toml.push_str(&format!("host = \"{}\"\n", config.server.host));
        toml.push_str(&format!("port = {}\n", config.server.port));
        toml.push_str(&format!(
            "environment = \"{}\"\n",
            config.server.environment
        ));
        toml.push_str(&format!("workers = {}\n", config.server.workers));
        toml.push_str("\n");

        // Database section
        if let Some(db) = &config.database {
            toml.push_str("[database]\n");
            toml.push_str(&format!("url = \"{}\"\n", db.url));
            toml.push_str(&format!("max_connections = {}\n", db.max_connections));
            toml.push_str(&format!("enable_logging = {}\n", db.enable_logging));
            toml.push_str("\n");
        }

        // Authentication section
        if let Some(auth) = &config.auth {
            toml.push_str("[auth.jwt]\n");
            if !auth.jwt_secret.is_empty() {
                toml.push_str(&format!("secret = \"{}\"\n", auth.jwt_secret));
            } else {
                toml.push_str("secret = \"your-secret-key-here\"\n");
            }
            toml.push_str(&format!("expiration = {}\n", auth.session_timeout * 60));
            toml.push_str("\n");

            toml.push_str("[auth.security]\n");
            toml.push_str(&format!(
                "max_login_attempts = {}\n",
                auth.max_login_attempts
            ));
            toml.push_str(&format!(
                "require_email_verification = {}\n",
                auth.require_email_verification
            ));
            toml.push_str("\n");
        }

        // OAuth section
        if let Some(oauth) = &config.oauth {
            if oauth.enabled {
                toml.push_str("[oauth]\n");
                toml.push_str("enabled = true\n\n");

                if let Some(google) = &oauth.google {
                    toml.push_str("[oauth.google]\n");
                    toml.push_str(&format!("client_id = \"{}\"\n", google.client_id));
                    toml.push_str(&format!("client_secret = \"{}\"\n", google.client_secret));
                    toml.push_str(&format!("redirect_uri = \"{}\"\n", google.redirect_uri));
                    toml.push_str("\n");
                }

                if let Some(github) = &oauth.github {
                    toml.push_str("[oauth.github]\n");
                    toml.push_str(&format!("client_id = \"{}\"\n", github.client_id));
                    toml.push_str(&format!("client_secret = \"{}\"\n", github.client_secret));
                    toml.push_str(&format!("redirect_uri = \"{}\"\n", github.redirect_uri));
                    toml.push_str("\n");
                }

                if let Some(microsoft) = &oauth.microsoft {
                    toml.push_str("[oauth.microsoft]\n");
                    toml.push_str(&format!("client_id = \"{}\"\n", microsoft.client_id));
                    toml.push_str(&format!(
                        "client_secret = \"{}\"\n",
                        microsoft.client_secret
                    ));
                    toml.push_str(&format!("redirect_uri = \"{}\"\n", microsoft.redirect_uri));
                    toml.push_str("\n");
                }
            }
        }

        // Email section
        if let Some(email) = &config.email {
            toml.push_str("[email]\n");
            toml.push_str(&format!("smtp_host = \"{}\"\n", email.smtp_host));
            toml.push_str(&format!("smtp_port = {}\n", email.smtp_port));
            toml.push_str(&format!("smtp_username = \"{}\"\n", email.smtp_username));
            toml.push_str(&format!("smtp_password = \"{}\"\n", email.smtp_password));
            toml.push_str(&format!("from_email = \"{}\"\n", email.from_email));
            toml.push_str(&format!("from_name = \"{}\"\n", email.from_name));
            toml.push_str("\n");
        }

        // Security section
        toml.push_str("[security]\n");
        toml.push_str(&format!("enable_csrf = {}\n", config.security.enable_csrf));
        toml.push_str(&format!(
            "rate_limit_requests = {}\n",
            config.security.rate_limit_requests
        ));
        toml.push_str(&format!("bcrypt_cost = {}\n", config.security.bcrypt_cost));
        toml.push_str("\n");

        // SSL section
        if let Some(ssl) = &config.ssl {
            toml.push_str("[ssl]\n");
            toml.push_str(&format!("force_https = {}\n", ssl.force_https));
            if !ssl.cert_path.is_empty() {
                toml.push_str(&format!("cert_path = \"{}\"\n", ssl.cert_path));
            }
            if !ssl.key_path.is_empty() {
                toml.push_str(&format!("key_path = \"{}\"\n", ssl.key_path));
            }
            toml.push_str("\n");
        }

        // Monitoring section
        if let Some(monitoring) = &config.monitoring {
            if monitoring.enabled {
                toml.push_str("[monitoring]\n");
                toml.push_str("enabled = true\n");
                toml.push_str(&format!("metrics_port = {}\n", monitoring.metrics_port));
                toml.push_str(&format!(
                    "prometheus_enabled = {}\n",
                    monitoring.prometheus_enabled
                ));
                toml.push_str("\n");
            }
        }

        // Cache section
        if let Some(cache) = &config.cache {
            if cache.enabled {
                toml.push_str("[cache]\n");
                toml.push_str("enabled = true\n");
                toml.push_str(&format!("type = \"{}\"\n", cache.cache_type));
                toml.push_str(&format!("default_ttl = {}\n", cache.default_ttl));
                toml.push_str("\n");
            }
        }

        // Build info section
        toml.push_str("[build_info]\n");
        toml.push_str(&format!(
            "environment = \"{}\"\n",
            config.server.environment
        ));
        toml.push_str("config_version = \"1.0.0\"\n");

        toml
    }

    pub fn generate_cargo_features(&self, config: &WizardConfig) -> String {
        let features: Vec<String> = config
            .selected_features
            .iter()
            .map(|f| format!("\"{}\"", f))
            .collect();

        format!("default = [{}]", features.join(", "))
    }

    pub fn update_cargo_toml(
        &self,
        config: &WizardConfig,
        cargo_path: &Path,
    ) -> Result<(), Box<dyn std::error::Error>> {
        let content = fs::read_to_string(cargo_path)?;
        let lines: Vec<&str> = content.lines().collect();
        let mut new_lines = Vec::new();
        let mut in_features = false;
        let mut features_updated = false;

        for line in lines {
            if line.trim().starts_with("[features]") {
                in_features = true;
                new_lines.push(line.to_string());
            } else if in_features && line.trim().starts_with("default = [") {
                // Replace the default features line
                new_lines.push(self.generate_cargo_features(config));
                features_updated = true;
                in_features = false;
            } else if in_features && line.trim().starts_with("[") {
                // Exiting features section
                if !features_updated {
                    new_lines.push(self.generate_cargo_features(config));
                }
                new_lines.push(line.to_string());
                in_features = false;
            } else {
                new_lines.push(line.to_string());
            }
        }

        let updated_content = new_lines.join("\n");
        fs::write(cargo_path, updated_content)?;
        Ok(())
    }
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let wizard = ConfigWizard::new();

    match wizard.run_wizard() {
        Ok(config) => {
            println!("\n=== Configuration Summary ===");
            println!("Selected features: {:?}", config.selected_features);
            println!("Server: {}:{}", config.server.host, config.server.port);
            println!("Environment: {}", config.server.environment);

            if wizard.ask_yes_no("\nGenerate configuration files?")? {
                // Generate config.toml in project root
                let toml_content = wizard.generate_config_toml(&config);
                fs::write("../config.toml", &toml_content)?;
                println!("✓ Generated config.toml");

                // Update Cargo.toml - try different possible paths
                let possible_paths = vec![
                    Path::new("server/Cargo.toml"), // From project root
                    Path::new("Cargo.toml"),        // From server directory
                    Path::new("../Cargo.toml"),     // From subdirectory
                ];

                if let Some(cargo_path) = possible_paths.iter().find(|path| path.exists()) {
                    wizard.update_cargo_toml(&config, cargo_path)?;
                    println!("✓ Updated Cargo.toml default features");
                } else {
                    println!("⚠ Cargo.toml not found in any expected location, skipping update");
                }

                println!("\nConfiguration files generated successfully!");
                println!(
                    "Default features: {}",
                    wizard.generate_cargo_features(&config)
                );

                println!("\n=== Next Steps ===");
                println!("1. Review the generated config.toml file");
                println!("2. Update any placeholder values (like OAuth secrets)");
                println!("3. Run 'cargo build' to verify the feature selection");
                println!("4. Start your application with 'cargo run'");
            }
        }
        Err(e) => {
            eprintln!("Error running wizard: {}", e);
            return Err(e);
        }
    }

    Ok(())
}
