//! Configuration Management CLI Tool
//!
//! This tool helps manage configuration files and validate settings.
//!
//! Usage:
//!   cargo run --bin config_tool -- validate
//!   cargo run --bin config_tool -- show
//!   cargo run --bin config_tool -- generate --env dev
//!   cargo run --bin config_tool -- check-env
//!   cargo run --bin config_tool -- encrypt "value"
//!   cargo run --bin config_tool -- decrypt "@encrypted_value"

use clap::{Parser, Subcommand};
use server::config::Config;
#[cfg(feature = "crypto")]
use server::config::encryption::EncryptionTool;
use server::utils;
use std::env;
use std::fs;
use std::path::Path;

#[derive(Parser)]
#[command(name = "config_tool")]
#[command(about = "Configuration management tool")]
#[command(version)]
struct Cli {
    /// Root path for configuration
    #[arg(short, long, default_value = ".")]
    root_path: String,

    #[command(subcommand)]
    command: Commands,
}

#[derive(Subcommand)]
enum Commands {
    /// Validate configuration
    Validate,
    /// Show current configuration
    Show,
    /// Generate configuration file
    Generate {
        /// Environment (dev, prod)
        #[arg(short, long, default_value = "dev")]
        environment: String,
    },
    /// Check environment variables
    CheckEnv,
    /// Encrypt a configuration value
    Encrypt {
        /// Value to encrypt
        value: String,
    },
    /// Decrypt a configuration value
    Decrypt {
        /// Encrypted value to decrypt
        encrypted: String,
    },
    /// Show encryption key information
    KeyInfo,
    /// Verify encryption key
    VerifyKey,
}

// Default configuration templates
const DEFAULT_CONFIG_TOML: &str = r#"
# Main Configuration File
[server]
protocol = "http"
host = "127.0.0.1"
port = 3030
environment = "dev"
log_level = "info"

[database]
url = "postgresql://dev:dev@localhost:5432/rustelo_dev"
max_connections = 5
min_connections = 1
connect_timeout = 30
idle_timeout = 600
max_lifetime = 1800

[session]
secret = "your-secret-key-here"
cookie_name = "session_id"
cookie_secure = false
cookie_http_only = true
cookie_same_site = "lax"
max_age = 3600

[cors]
allowed_origins = ["http://localhost:3030"]
allowed_methods = ["GET", "POST", "PUT", "DELETE", "OPTIONS"]
allowed_headers = ["Content-Type", "Authorization"]
allow_credentials = true
max_age = 3600

[static]
assets_dir = "public"
site_root = "target/site"
site_pkg_dir = "pkg"

[server_dirs]
public_dir = "public"
uploads_dir = "uploads"
logs_dir = "logs"
temp_dir = "tmp"
cache_dir = "cache"
config_dir = "config"
data_dir = "data"
backup_dir = "backups"

[security]
enable_csrf = false
csrf_token_name = "csrf_token"
rate_limit_requests = 100
rate_limit_window = 60
bcrypt_cost = 4

[oauth]
enabled = false

[oauth.google]
client_id = ""
client_secret = ""
redirect_uri = "http://localhost:3030/auth/google/callback"

[oauth.github]
client_id = ""
client_secret = ""
redirect_uri = "http://localhost:3030/auth/github/callback"

[email]
enabled = false
smtp_host = "localhost"
smtp_port = 587
smtp_username = ""
smtp_password = ""
from_email = "noreply@example.com"
from_name = "Rustelo App"

[redis]
enabled = false
url = "redis://localhost:6379"
pool_size = 10
connection_timeout = 5
command_timeout = 5

[app]
name = "Rustelo App"
version = "0.1.0"
debug = true
enable_metrics = true
enable_health_check = true
enable_compression = false
max_request_size = 10485760

[logging]
format = "text"
level = "info"
file_path = "logs/app.log"
max_file_size = 10485760
max_files = 5
enable_console = true
enable_file = true

[content]
enabled = false
content_dir = "content"
cache_enabled = false
cache_ttl = 3600
max_file_size = 5242880

[features]
auth = true
tls = false
content_db = true
two_factor_auth = false
"#;

const DEFAULT_DEV_CONFIG_TOML: &str = r#"
# Development Configuration
[server]
protocol = "http"
host = "127.0.0.1"
port = 3030
environment = "dev"
log_level = "debug"

[database]
url = "postgresql://dev:dev@localhost:5432/rustelo_dev"
max_connections = 5
min_connections = 1
connect_timeout = 30
idle_timeout = 600
max_lifetime = 1800

[session]
secret = "dev-secret-not-for-production"
cookie_name = "session_id"
cookie_secure = false
cookie_http_only = true
cookie_same_site = "lax"
max_age = 7200

[cors]
allowed_origins = ["http://localhost:3030", "http://127.0.0.1:3030"]
allowed_methods = ["GET", "POST", "PUT", "DELETE", "OPTIONS"]
allowed_headers = ["Content-Type", "Authorization", "X-Requested-With"]
allow_credentials = true
max_age = 3600

[static]
assets_dir = "public"
site_root = "target/site"
site_pkg_dir = "pkg"

[server_dirs]
public_dir = "public"
uploads_dir = "uploads"
logs_dir = "logs"
temp_dir = "tmp"
cache_dir = "cache"
config_dir = "config"
data_dir = "data"
backup_dir = "backups"

[security]
enable_csrf = false
csrf_token_name = "csrf_token"
rate_limit_requests = 1000
rate_limit_window = 60
bcrypt_cost = 4

[oauth]
enabled = false

[oauth.google]
client_id = ""
client_secret = ""
redirect_uri = "http://localhost:3030/auth/google/callback"

[oauth.github]
client_id = ""
client_secret = ""
redirect_uri = "http://localhost:3030/auth/github/callback"

[email]
enabled = false
smtp_host = "localhost"
smtp_port = 587
smtp_username = ""
smtp_password = ""
from_email = "noreply@example.com"
from_name = "Rustelo App"

[redis]
enabled = false
url = "redis://localhost:6379"
pool_size = 10
connection_timeout = 5
command_timeout = 5

[app]
name = "Rustelo App"
version = "0.1.0"
debug = true
enable_metrics = true
enable_health_check = true
enable_compression = false
max_request_size = 52428800

[logging]
format = "text"
level = "debug"
file_path = "logs/app.log"
max_file_size = 10485760
max_files = 5
enable_console = true
enable_file = true

[content]
enabled = false
content_dir = "content"
cache_enabled = false
cache_ttl = 3600
max_file_size = 5242880

[features]
auth = true
tls = false
content_db = true
two_factor_auth = false
"#;

const DEFAULT_PROD_CONFIG_TOML: &str = r#"
# Production Configuration
[server]
protocol = "https"
host = "0.0.0.0"
port = 443
environment = "prod"
log_level = "info"

[server.tls]
cert_path = "certs/server.crt"
key_path = "certs/server.key"

[database]
url = "postgresql://prod:${DATABASE_PASSWORD}@db.example.com:5432/rustelo_prod"
max_connections = 20
min_connections = 1
connect_timeout = 30
idle_timeout = 600
max_lifetime = 1800

[session]
secret = "${SESSION_SECRET}"
cookie_name = "session_id"
cookie_secure = true
cookie_http_only = true
cookie_same_site = "strict"
max_age = 3600

[cors]
allowed_origins = ["https://yourdomain.com"]
allowed_methods = ["GET", "POST", "PUT", "DELETE", "OPTIONS"]
allowed_headers = ["Content-Type", "Authorization", "X-Requested-With"]
allow_credentials = true
max_age = 3600

[static]
assets_dir = "public"
site_root = "target/site"
site_pkg_dir = "pkg"

[server_dirs]
public_dir = "/var/www/public"
uploads_dir = "/var/www/uploads"
logs_dir = "/var/log/app"
temp_dir = "/tmp/app"
cache_dir = "/var/cache/app"
config_dir = "/etc/app"
data_dir = "/var/lib/app"
backup_dir = "/var/backups/app"

[security]
enable_csrf = true
csrf_token_name = "csrf_token"
rate_limit_requests = 50
rate_limit_window = 60
bcrypt_cost = 12

[oauth]
enabled = false

[oauth.google]
client_id = "${GOOGLE_CLIENT_ID}"
client_secret = "${GOOGLE_CLIENT_SECRET}"
redirect_uri = "https://yourdomain.com/auth/google/callback"

[oauth.github]
client_id = "${GITHUB_CLIENT_ID}"
client_secret = "${GITHUB_CLIENT_SECRET}"
redirect_uri = "https://yourdomain.com/auth/github/callback"

[email]
enabled = false
smtp_host = "smtp.gmail.com"
smtp_port = 587
smtp_username = "${SMTP_USERNAME}"
smtp_password = "${SMTP_PASSWORD}"
from_email = "noreply@example.com"
from_name = "Rustelo App"

[redis]
enabled = false
url = "redis://localhost:6379"
pool_size = 10
connection_timeout = 5
command_timeout = 5

[app]
name = "Rustelo App"
version = "0.1.0"
debug = false
enable_metrics = true
enable_health_check = true
enable_compression = true
max_request_size = 5242880

[logging]
format = "json"
level = "info"
file_path = "logs/app.log"
max_file_size = 10485760
max_files = 5
enable_console = true
enable_file = true

[content]
enabled = false
content_dir = "content"
cache_enabled = true
cache_ttl = 3600
max_file_size = 5242880

[features]
auth = true
tls = true
content_db = true
two_factor_auth = false
"#;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let cli = Cli::parse();

    match cli.command {
        Commands::Validate => validate_config(&cli.root_path),
        Commands::Show => show_config(&cli.root_path),
        Commands::Generate { environment } => generate_config(&environment),
        Commands::CheckEnv => check_env_vars(),
        #[cfg(feature = "crypto")]
        Commands::Encrypt { value } => encrypt_value(&cli.root_path, &value)?,
        #[cfg(feature = "crypto")]
        Commands::Decrypt { encrypted } => decrypt_value(&cli.root_path, &encrypted)?,
        #[cfg(feature = "crypto")]
        Commands::KeyInfo => show_key_info(&cli.root_path)?,
        #[cfg(feature = "crypto")]
        Commands::VerifyKey => verify_encryption_key(&cli.root_path)?,
        #[cfg(not(feature = "crypto"))]
        Commands::Encrypt { value: _ } => {
            println!("❌ Encryption functionality requires the 'crypto' feature to be enabled");
            std::process::exit(1);
        }
        #[cfg(not(feature = "crypto"))]
        Commands::Decrypt { encrypted: _ } => {
            println!("❌ Decryption functionality requires the 'crypto' feature to be enabled");
            std::process::exit(1);
        }
        #[cfg(not(feature = "crypto"))]
        Commands::KeyInfo => {
            println!("❌ Key info functionality requires the 'crypto' feature to be enabled");
            std::process::exit(1);
        }
        #[cfg(not(feature = "crypto"))]
        Commands::VerifyKey => {
            println!(
                "❌ Key verification functionality requires the 'crypto' feature to be enabled"
            );
            std::process::exit(1);
        }
    }

    Ok(())
}

fn validate_config(_root_path: &str) {
    println!("🔍 Validating configuration...\n");

    match Config::load() {
        Ok(config) => match config.validate() {
            Ok(_) => {
                println!("✅ Configuration is valid!");
                println!("   Server: {}:{}", config.server.host, config.server.port);
                println!("   Environment: {:?}", config.server.environment);
                println!("   Protocol: {:?}", config.server.protocol);

                if config.requires_tls() {
                    println!("   TLS: Enabled");
                    if let Some(tls) = &config.server.tls {
                        println!("     Certificate: {}", tls.cert_path.display());
                        println!("     Private Key: {}", tls.key_path.display());
                    }
                } else {
                    println!("   TLS: Disabled");
                }
            }
            Err(e) => {
                println!("❌ Configuration validation failed: {}", e);
                std::process::exit(1);
            }
        },
        Err(e) => {
            println!("❌ Failed to load configuration: {}", e);
            std::process::exit(1);
        }
    }
}

fn show_config(root_path: &str) {
    println!("📋 Current configuration:\n");
    println!("Root Path: {}\n", root_path);

    match Config::load() {
        Ok(config) => {
            println!("=== Server Configuration ===");
            println!("Protocol: {:?}", config.server.protocol);
            println!("Host: {}", config.server.host);
            println!("Port: {}", config.server.port);
            println!("Environment: {:?}", config.server.environment);
            println!("Log Level: {}", config.server.log_level);
            println!("Server Address: {}", config.server_address());
            println!("Server URL: {}", config.server_url());

            println!("\n=== Database Configuration ===");
            println!("URL: {}", config.database.url);
            println!("Max Connections: {}", config.database.max_connections);
            println!("Min Connections: {}", config.database.min_connections);
            println!("Connect Timeout: {}s", config.database.connect_timeout);
            println!("Idle Timeout: {}s", config.database.idle_timeout);
            println!("Max Lifetime: {}s", config.database.max_lifetime);

            println!("\n=== Session Configuration ===");
            println!("Cookie Name: {}", config.session.cookie_name);
            println!("Cookie Secure: {}", config.session.cookie_secure);
            println!("Cookie HTTP Only: {}", config.session.cookie_http_only);
            println!("Cookie Same Site: {}", config.session.cookie_same_site);
            println!("Max Age: {}s", config.session.max_age);
            println!(
                "Secret: {}",
                if config.session.secret.is_empty() {
                    "❌ Not set"
                } else {
                    "✅ Set"
                }
            );

            println!("\n=== CORS Configuration ===");
            println!("Allowed Origins: {:?}", config.cors.allowed_origins);
            println!("Allowed Methods: {:?}", config.cors.allowed_methods);
            println!("Allowed Headers: {:?}", config.cors.allowed_headers);
            println!("Allow Credentials: {}", config.cors.allow_credentials);
            println!("Max Age: {}s", config.cors.max_age);

            println!("\n=== Security Configuration ===");
            println!("CSRF Enabled: {}", config.security.enable_csrf);
            println!("CSRF Token Name: {}", config.security.csrf_token_name);
            println!(
                "Rate Limit: {} requests / {} seconds",
                config.security.rate_limit_requests, config.security.rate_limit_window
            );
            println!("BCrypt Cost: {}", config.security.bcrypt_cost);

            println!("\n=== Application Configuration ===");
            println!("Name: {}", config.app.name);
            println!("Version: {}", config.app.version);
            println!("Debug: {}", config.app.debug);
            println!("Metrics: {}", config.app.enable_metrics);
            println!("Health Check: {}", config.app.enable_health_check);
            println!("Compression: {}", config.app.enable_compression);
            println!("Max Request Size: {} bytes", config.app.max_request_size);

            println!("\n=== Feature Flags ===");
            println!("Auth: {:?}", config.features.auth);
            println!("RBAC: {:?}", config.features.rbac);
            println!("Content: {:?}", config.features.content);
            println!("Security: {:?}", config.features.security);

            println!("=== Static Files ===");
            println!("Assets Dir: {}", config.static_files.assets_dir);
            println!("Site Root: {}", config.static_files.site_root);
            println!("Site Package Dir: {}", config.static_files.site_pkg_dir);

            println!("\n=== Server Directories ===");
            println!("Public Dir: {}", config.server_dirs.public_dir);
            println!("Uploads Dir: {}", config.server_dirs.uploads_dir);
            println!("Logs Dir: {}", config.server_dirs.logs_dir);
            println!("Temp Dir: {}", config.server_dirs.temp_dir);
            println!("Cache Dir: {}", config.server_dirs.cache_dir);
            println!("Config Dir: {}", config.server_dirs.config_dir);
            println!("Data Dir: {}", config.server_dirs.data_dir);
            println!("Backup Dir: {}", config.server_dirs.backup_dir);

            println!("\n=== OAuth Configuration ===");
            println!("OAuth Enabled: {}", config.oauth.enabled);
            if let Some(google) = &config.oauth.google {
                println!("Google OAuth: ✅ Configured");
                println!("  Client ID: {}", google.client_id);
                println!("  Redirect URI: {}", google.redirect_uri);
            } else {
                println!("Google OAuth: ❌ Not configured");
            }

            if let Some(github) = &config.oauth.github {
                println!("GitHub OAuth: ✅ Configured");
                println!("  Client ID: {}", github.client_id);
                println!("  Redirect URI: {}", github.redirect_uri);
            } else {
                println!("GitHub OAuth: ❌ Not configured");
            }

            println!("\n=== Email Configuration ===");
            println!("Email Enabled: {}", config.email.enabled);
            if config.email.enabled {
                println!("SMTP Host: {}", config.email.smtp_host);
                println!("SMTP Port: {}", config.email.smtp_port);
                println!("From Email: {}", config.email.from_email);
                println!("From Name: {}", config.email.from_name);
            }

            println!("\n=== Redis Configuration ===");
            println!("Redis Enabled: {}", config.redis.enabled);
            if config.redis.enabled {
                println!("Redis URL: {}", config.redis.url);
                println!("Pool Size: {}", config.redis.pool_size);
            }

            println!("\n=== Logging Configuration ===");
            println!("Format: {}", config.logging.format);
            println!("Level: {}", config.logging.level);
            println!("File Path: {}", config.logging.file_path);
            println!("Console Logging: {}", config.logging.enable_console);
            println!("File Logging: {}", config.logging.enable_file);

            println!("\n=== Content Configuration ===");
            #[cfg(feature = "content-db")]
            {
                println!("Content Enabled: {}", config.content.enabled);
                if config.content.enabled {
                    println!("Content Dir: {}", config.content.content_dir);
                    println!("Cache Enabled: {}", config.content.cache_enabled);
                    println!("Cache TTL: {}s", config.content.cache_ttl);
                }
            }
            #[cfg(not(feature = "content-db"))]
            {
                println!("Content Enabled: {}", config.features.content.enabled);
                if config.features.content.enabled {
                    println!(
                        "Content management features are available but content-db feature is not enabled"
                    );
                }
            }
        }
        Err(e) => {
            println!("❌ Failed to load configuration: {}", e);
            std::process::exit(1);
        }
    }
}

fn generate_config(environment: &str) {
    println!(
        "🔧 Generating configuration for environment: {}\n",
        environment
    );

    // Initialize path utilities
    utils::init();

    let config_content = match environment {
        "dev" | "development" => {
            utils::config::read_config_or_embedded("config.dev.toml", DEFAULT_DEV_CONFIG_TOML)
        }
        "prod" | "production" => {
            utils::config::read_config_or_embedded("config.prod.toml", DEFAULT_PROD_CONFIG_TOML)
        }
        _ => utils::config::read_config_or_embedded("config.toml", DEFAULT_CONFIG_TOML),
    };

    let filename = format!("config.{}.toml", environment);

    if Path::new(&filename).exists() {
        println!("⚠️  File {} already exists. Overwrite? (y/N)", filename);
        let mut input = String::new();
        std::io::stdin()
            .read_line(&mut input)
            .expect("Failed to read input");

        if !input.trim().to_lowercase().starts_with('y') {
            println!("❌ Operation cancelled.");
            return;
        }
    }

    match fs::write(&filename, config_content) {
        Ok(_) => {
            println!("✅ Configuration file generated: {}", filename);
            println!("   Please review and customize the settings as needed.");
            println!("   Remember to set environment variables for sensitive data!");
        }
        Err(e) => {
            println!("❌ Failed to write configuration file: {}", e);
            std::process::exit(1);
        }
    }
}

fn check_env_vars() {
    println!("🔍 Checking environment variables...\n");

    let required_vars = vec![
        ("DATABASE_URL", "Database connection string"),
        ("SESSION_SECRET", "Session encryption secret"),
    ];

    let optional_vars = vec![
        ("SERVER_HOST", "Server bind address"),
        ("SERVER_PORT", "Server port"),
        ("ENVIRONMENT", "Runtime environment"),
        ("LOG_LEVEL", "Logging level"),
        ("TLS_CERT_PATH", "TLS certificate path"),
        ("TLS_KEY_PATH", "TLS private key path"),
        ("GOOGLE_CLIENT_ID", "Google OAuth client ID"),
        ("GOOGLE_CLIENT_SECRET", "Google OAuth client secret"),
        ("GITHUB_CLIENT_ID", "GitHub OAuth client ID"),
        ("GITHUB_CLIENT_SECRET", "GitHub OAuth client secret"),
        ("SMTP_USERNAME", "SMTP username"),
        ("SMTP_PASSWORD", "SMTP password"),
    ];

    println!("=== Required Environment Variables ===");
    let mut missing_required = false;

    for (var, description) in &required_vars {
        match env::var(var) {
            Ok(value) => {
                if value.is_empty() {
                    println!("❌ {}: Empty ({})", var, description);
                    missing_required = true;
                } else {
                    println!("✅ {}: Set ({})", var, description);
                }
            }
            Err(_) => {
                println!("❌ {}: Not set ({})", var, description);
                missing_required = true;
            }
        }
    }

    println!("\n=== Optional Environment Variables ===");
    for (var, description) in &optional_vars {
        match env::var(var) {
            Ok(value) => {
                if value.is_empty() {
                    println!("⚠️  {}: Empty ({})", var, description);
                } else {
                    println!("✅ {}: Set ({})", var, description);
                }
            }
            Err(_) => {
                println!("ℹ️  {}: Not set ({})", var, description);
            }
        }
    }

    if missing_required {
        println!("\n❌ Some required environment variables are missing!");
        println!("   Please set them before running the application.");
        std::process::exit(1);
    } else {
        println!("\n✅ All required environment variables are set!");
    }
}

#[cfg(feature = "crypto")]
fn encrypt_value(root_path: &str, value: &str) -> Result<(), Box<dyn std::error::Error>> {
    println!("🔐 Encrypting value...\n");

    let tool = EncryptionTool::new(root_path)?;
    let encrypted = tool.encrypt_value(value)?;

    println!("✅ Encrypted value: {}", encrypted);
    println!("\nUse this in your configuration file:");
    println!("some_key = \"{}\"", encrypted);

    Ok(())
}

#[cfg(feature = "crypto")]
fn decrypt_value(root_path: &str, encrypted: &str) -> Result<(), Box<dyn std::error::Error>> {
    println!("🔓 Decrypting value...\n");

    let tool = EncryptionTool::new(root_path)?;
    let decrypted = tool.decrypt_value(encrypted)?;

    println!("✅ Decrypted value: {}", decrypted);

    Ok(())
}

#[cfg(feature = "crypto")]
fn show_key_info(root_path: &str) -> Result<(), Box<dyn std::error::Error>> {
    println!("🔑 Encryption key information:\n");

    let tool = EncryptionTool::new(root_path)?;
    let info = tool.show_key_info()?;

    println!("{}", info);

    Ok(())
}

#[cfg(feature = "crypto")]
fn verify_encryption_key(root_path: &str) -> Result<(), Box<dyn std::error::Error>> {
    println!("🔍 Verifying encryption key...\n");

    let tool = EncryptionTool::new(root_path)?;
    tool.verify_key()?;

    println!("✅ Encryption key verification successful!");

    Ok(())
}
