//! Configuration Encryption Tool
//!
//! This tool provides command-line utilities for managing encrypted configuration values
//! using the .k file approach. Configuration values starting with '@' are automatically
//! encrypted/decrypted using the AES-256-GCM key stored in the .k file.

use clap::{Parser, Subcommand};
use server::config::encryption::{ConfigEncryption, EncryptionTool};
use std::fs;
use std::io::{self, Write};
use std::path::Path;

#[derive(Parser)]
#[command(name = "config_crypto_tool")]
#[command(about = "CLI tool for managing encrypted configuration values with .k file")]
#[command(version)]
struct Cli {
    /// Root path for configuration (where .k file is located)
    #[arg(short, long, default_value = ".")]
    root_path: String,

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

#[derive(Subcommand)]
enum Commands {
    /// Generate a new encryption key (.k file)
    GenerateKey {
        /// Force overwrite existing key
        #[arg(short, long)]
        force: bool,
    },

    /// Encrypt a value for use in configuration
    Encrypt {
        /// Value to encrypt
        value: String,
        /// Show the original value for confirmation
        #[arg(short, long)]
        show: bool,
    },

    /// Decrypt an encrypted value
    Decrypt {
        /// Encrypted value (starting with @)
        encrypted: String,
    },

    /// Show information about the encryption key
    KeyInfo,

    /// Verify the encryption key works correctly
    Verify,

    /// Rotate the encryption key (WARNING: requires re-encryption of all values)
    RotateKey {
        /// Confirm the rotation (required to prevent accidents)
        #[arg(long)]
        confirm: bool,
    },

    /// Find all encrypted values in a configuration file
    FindEncrypted {
        /// Configuration file path
        #[arg(short, long)]
        config: String,
    },

    /// Show decrypted values from configuration file (for debugging)
    ShowDecrypted {
        /// Configuration file path
        #[arg(short, long)]
        config: String,
    },

    /// Encrypt all sensitive values in a configuration file
    EncryptConfig {
        /// Configuration file path
        #[arg(short, long)]
        config: String,
        /// Keys to encrypt (comma-separated)
        #[arg(short, long)]
        keys: String,
        /// Backup original file
        #[arg(short, long)]
        backup: bool,
    },

    /// Interactive mode for managing configuration encryption
    Interactive,
}

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

    match run(cli).await {
        Ok(()) => {}
        Err(e) => {
            eprintln!("Error: {}", e);
            std::process::exit(1);
        }
    }

    Ok(())
}

async fn run(cli: Cli) -> Result<(), Box<dyn std::error::Error>> {
    let root_path = &cli.root_path;

    match cli.command {
        Commands::GenerateKey { force } => {
            let key_path = Path::new(root_path).join(".k");

            if key_path.exists() && !force {
                eprintln!("Encryption key already exists at {:?}", key_path);
                eprintln!("Use --force to overwrite or 'rotate-key' to safely rotate");
                return Ok(());
            }

            if key_path.exists() {
                println!("Overwriting existing encryption key...");
            }

            let mut encryption = ConfigEncryption::new(root_path)?;
            if key_path.exists() {
                encryption.rotate_key()?;
            }

            println!("✓ Encryption key generated at {:?}", key_path);
            println!("⚠️  Keep this file secure and backed up!");
        }

        Commands::Encrypt { value, show } => {
            let encryption = ConfigEncryption::new(root_path)?;
            let encrypted = encryption.encrypt(&value)?;

            println!("Encrypted value: {}", encrypted);
            if show {
                println!("Original value: {}", value);
            }
            println!();
            println!("Use this in your configuration file:");
            println!("some_key = \"{}\"", encrypted);
        }

        Commands::Decrypt { encrypted } => {
            let encryption = ConfigEncryption::new(root_path)?;
            let decrypted = encryption.decrypt(&encrypted)?;

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

        Commands::KeyInfo => {
            let tool = EncryptionTool::new(root_path)?;
            let info = tool.show_key_info()?;
            println!("{}", info);
        }

        Commands::Verify => {
            let encryption = ConfigEncryption::new(root_path)?;
            encryption.verify_key()?;
            println!("✓ Encryption key verification successful");
        }

        Commands::RotateKey { confirm } => {
            if !confirm {
                eprintln!("Key rotation requires --confirm flag");
                eprintln!("WARNING: This will create a new key. You must re-encrypt all values!");
                return Ok(());
            }

            let mut encryption = ConfigEncryption::new(root_path)?;
            encryption.rotate_key()?;
            println!("✓ Encryption key rotated successfully");
            println!("⚠️  You must now re-encrypt all configuration values!");
        }

        Commands::FindEncrypted { config } => {
            let tool = EncryptionTool::new(root_path)?;
            let config_content = fs::read_to_string(&config)?;
            let encrypted_values = tool.find_encrypted_values(&config_content);

            if encrypted_values.is_empty() {
                println!("No encrypted values found in {}", config);
            } else {
                println!(
                    "Found {} encrypted values in {}:",
                    encrypted_values.len(),
                    config
                );
                for (i, value) in encrypted_values.iter().enumerate() {
                    println!("  {}: {}", i + 1, value);
                }
            }
        }

        Commands::ShowDecrypted { config } => {
            let tool = EncryptionTool::new(root_path)?;
            let config_content = fs::read_to_string(&config)?;
            let decrypted_content = tool.decrypt_config_display(&config_content)?;

            println!("Configuration with decrypted values:");
            println!("{}", decrypted_content);
        }

        Commands::EncryptConfig {
            config,
            keys,
            backup,
        } => {
            let encryption = ConfigEncryption::new(root_path)?;
            let config_content = fs::read_to_string(&config)?;

            if backup {
                let backup_path = format!("{}.backup", config);
                fs::copy(&config, &backup_path)?;
                println!("✓ Backup created at {}", backup_path);
            }

            let keys_to_encrypt: Vec<&str> = keys.split(',').map(|k| k.trim()).collect();
            let mut updated_content = config_content.clone();

            for key in keys_to_encrypt {
                // Simple regex-based replacement for TOML values
                let pattern = format!(r#"{}\s*=\s*"([^"]*)""#, regex::escape(key));
                let re = regex::Regex::new(&pattern)?;

                if let Some(captures) = re.captures(&config_content) {
                    let original_value = captures.get(1).map(|m| m.as_str()).unwrap_or("");
                    if !ConfigEncryption::is_encrypted(original_value) {
                        let encrypted_value = encryption.encrypt(original_value)?;
                        let replacement = format!(r#"{} = "{}""#, key, encrypted_value);
                        updated_content = re
                            .replace(&updated_content, replacement.as_str())
                            .to_string();
                        println!("✓ Encrypted key: {}", key);
                    } else {
                        println!("- Key already encrypted: {}", key);
                    }
                } else {
                    println!("⚠️  Key not found: {}", key);
                }
            }

            fs::write(&config, updated_content)?;
            println!("✓ Configuration updated: {}", config);
        }

        Commands::Interactive => {
            run_interactive_mode(root_path).await?;
        }
    }

    Ok(())
}

async fn run_interactive_mode(root_path: &str) -> Result<(), Box<dyn std::error::Error>> {
    println!("=== Configuration Encryption Tool - Interactive Mode ===");
    println!();

    let key_path = Path::new(root_path).join(".k");
    if !key_path.exists() {
        println!("No encryption key found. Creating new key...");
        let _encryption = ConfigEncryption::new(root_path)?;
        println!("✓ New encryption key created at {:?}", key_path);
        println!();
    }

    loop {
        println!("Select an option:");
        println!("1. Encrypt a value");
        println!("2. Decrypt a value");
        println!("3. Show key information");
        println!("4. Verify key");
        println!("5. Find encrypted values in config file");
        println!("6. Exit");
        print!("Enter choice (1-6): ");
        io::stdout().flush()?;

        let mut input = String::new();
        io::stdin().read_line(&mut input)?;
        let choice = input.trim();

        match choice {
            "1" => {
                print!("Enter value to encrypt: ");
                io::stdout().flush()?;
                let mut value = String::new();
                io::stdin().read_line(&mut value)?;
                let value = value.trim();

                let encryption = ConfigEncryption::new(root_path)?;
                let encrypted = encryption.encrypt(value)?;
                println!("Encrypted value: {}", encrypted);
                println!("Use this in your configuration file:");
                println!("some_key = \"{}\"", encrypted);
            }

            "2" => {
                print!("Enter encrypted value (starting with @): ");
                io::stdout().flush()?;
                let mut encrypted = String::new();
                io::stdin().read_line(&mut encrypted)?;
                let encrypted = encrypted.trim();

                let encryption = ConfigEncryption::new(root_path)?;
                match encryption.decrypt(encrypted) {
                    Ok(decrypted) => println!("Decrypted value: {}", decrypted),
                    Err(e) => println!("Failed to decrypt: {}", e),
                }
            }

            "3" => {
                let tool = EncryptionTool::new(root_path)?;
                let info = tool.show_key_info()?;
                println!("{}", info);
            }

            "4" => {
                let encryption = ConfigEncryption::new(root_path)?;
                match encryption.verify_key() {
                    Ok(()) => println!("✓ Encryption key verification successful"),
                    Err(e) => println!("✗ Key verification failed: {}", e),
                }
            }

            "5" => {
                print!("Enter config file path: ");
                io::stdout().flush()?;
                let mut config_path = String::new();
                io::stdin().read_line(&mut config_path)?;
                let config_path = config_path.trim();

                match fs::read_to_string(config_path) {
                    Ok(config_content) => {
                        let tool = EncryptionTool::new(root_path)?;
                        let encrypted_values = tool.find_encrypted_values(&config_content);

                        if encrypted_values.is_empty() {
                            println!("No encrypted values found in {}", config_path);
                        } else {
                            println!("Found {} encrypted values:", encrypted_values.len());
                            for (i, value) in encrypted_values.iter().enumerate() {
                                println!("  {}: {}", i + 1, value);
                            }
                        }
                    }
                    Err(e) => println!("Failed to read config file: {}", e),
                }
            }

            "6" => {
                println!("Goodbye!");
                break;
            }

            _ => {
                println!("Invalid choice. Please enter 1-6.");
            }
        }

        println!();
    }

    Ok(())
}
