use crate::core::audit;
use crate::core::constants::{CONFIG_FILE, NARU_DIR, SCHEMA_FILE};
use crate::core::models::{BackupData, ConfigFile, SchemaFile};
use crate::core::persistence;
use anyhow::{anyhow, Result};

pub struct BackupCreateCommand {
    pub file_path: String,
}

pub struct BackupRestoreCommand {
    pub file_path: String,
}

pub fn execute_create(cmd: BackupCreateCommand) -> Result<()> {
    let sanitized_path = crate::core::security::sanitize_file_path(&cmd.file_path)
        .map_err(|e| anyhow!("Invalid file path: {}", e))?;

    let mut config: ConfigFile = persistence::load_json(CONFIG_FILE)
        .map_err(|e| anyhow!("Failed to load config: {}. Run 'naru init' first.", e))?;

    for env_config in config.environments.values_mut() {
        env_config
            .entries
            .retain(|_, entry| !entry.is_secret || !entry.encrypted);
    }

    let schema: SchemaFile = persistence::load_json(SCHEMA_FILE).unwrap_or_else(|_| {
        eprintln!("Warning: Could not load schema file, using default schema");
        SchemaFile {
            version: "1.0".to_string(),
            fields: vec![],
        }
    });

    let backup_data = BackupData { config, schema };

    let json_data = serde_json::to_string_pretty(&backup_data)?;
    std::fs::write(
        sanitized_path
            .to_str()
            .ok_or_else(|| anyhow!("Invalid file path"))?,
        json_data,
    )?;
    println!("Backup created successfully at: {}", cmd.file_path);
    println!("Note: Encrypted secrets have been excluded from backup for security.");
    Ok(())
}

pub fn execute_restore(cmd: BackupRestoreCommand) -> Result<()> {
    let sanitized_path = crate::core::security::sanitize_file_path(&cmd.file_path)
        .map_err(|e| anyhow!("Invalid file path: {}", e))?;

    crate::core::security::check_file_size(&sanitized_path, 10 * 1024 * 1024)
        .map_err(|e| anyhow!("Backup file too large: {}", e))?;

    let content = std::fs::read_to_string(
        sanitized_path
            .to_str()
            .ok_or_else(|| anyhow!("Invalid file path"))?,
    )?;

    if content.len() > 10 * 1024 * 1024 {
        return Err(anyhow!("Backup file exceeds 10MB limit"));
    }

    let backup_data: BackupData =
        serde_json::from_str(&content).map_err(|e| anyhow!("Invalid backup file format: {}", e))?;

    if backup_data.config.environments.is_empty() {
        return Err(anyhow!("Backup file has no environments"));
    }
    for (env_name, env_config) in &backup_data.config.environments {
        if env_name.is_empty() {
            return Err(anyhow!("Backup contains empty environment name"));
        }
        for (key, entry) in &env_config.entries {
            if key.is_empty() {
                return Err(anyhow!(
                    "Backup contains empty key in environment {}",
                    env_name
                ));
            }
            if entry.value.len() > 1_000_000 {
                return Err(anyhow!(
                    "Backup contains excessively large value for key {}",
                    key
                ));
            }
        }
    }

    if backup_data.schema.version.is_empty() {
        return Err(anyhow!("Backup has invalid schema version"));
    }

    persistence::save_json(CONFIG_FILE, &backup_data.config)?;
    persistence::save_json(SCHEMA_FILE, &backup_data.schema)?;

    let log_path = format!("{}/audit.log", NARU_DIR);
    if let Err(e) = audit::log_action(
        "BACKUP_RESTORE",
        "all",
        None,
        None,
        Some(&cmd.file_path),
        &log_path,
    ) {
        eprintln!("Warning: Failed to log audit entry: {}", e);
    }

    println!(
        "Configuration restored successfully from: {}",
        cmd.file_path
    );
    Ok(())
}
