//! Unit tests for the KMS plugin.

use crate::error::{KmsError, KmsErrorKind};
use crate::helpers;

// =============================================================================
// Error Module Tests
// =============================================================================

#[test]
fn test_kms_error_display() {
    let error = KmsError::new(KmsErrorKind::EncryptionFailed, "AES encryption failed");
    let display = format!("{}", error);
    assert!(display.contains("encryption failed"));
    assert!(display.contains("AES"));
}

#[test]
fn test_kms_error_with_source() {
    let io_error = std::io::Error::new(std::io::ErrorKind::NotFound, "key file not found");
    let error = KmsError::with_source(KmsErrorKind::KeyNotFound, "failed to load key", io_error);
    assert!(error.to_string().contains("caused by"));
}

#[test]
fn test_kms_error_kind_display() {
    assert_eq!(KmsErrorKind::BackendNotAvailable.to_string(), "backend not available");
    assert_eq!(KmsErrorKind::EncryptionFailed.to_string(), "encryption failed");
    assert_eq!(KmsErrorKind::DecryptionFailed.to_string(), "decryption failed");
    assert_eq!(KmsErrorKind::KeyGenerationFailed.to_string(), "key generation failed");
    assert_eq!(KmsErrorKind::InvalidKeySpec.to_string(), "invalid key specification");
    assert_eq!(KmsErrorKind::NetworkError.to_string(), "network error");
}

#[test]
fn test_kms_error_convenience_constructors() {
    let error = KmsError::encryption_failed("test");
    assert_eq!(error.kind, KmsErrorKind::EncryptionFailed);

    let error = KmsError::decryption_failed("test");
    assert_eq!(error.kind, KmsErrorKind::DecryptionFailed);

    let error = KmsError::backend_not_available("test");
    assert_eq!(error.kind, KmsErrorKind::BackendNotAvailable);

    let error = KmsError::invalid_key_spec("test");
    assert_eq!(error.kind, KmsErrorKind::InvalidKeySpec);

    let error = KmsError::network_error("test");
    assert_eq!(error.kind, KmsErrorKind::NetworkError);
}

#[test]
fn test_kms_error_to_labeled_error() {
    let error = KmsError::new(KmsErrorKind::EncryptionFailed, "test error");
    let labeled: nu_protocol::LabeledError = error.into();
    assert!(format!("{:?}", labeled).contains("test error"));
}

// =============================================================================
// Backend Tests
// =============================================================================

#[test]
fn test_backend_new_age_invalid() {
    let result = helpers::Backend::new_age("invalid-recipient", None);
    assert!(result.is_err());
}

#[test]
fn test_backend_http_fallback() {
    let backend = helpers::Backend::new_http_fallback("cosmian", "http://localhost:8081");
    match backend {
        helpers::Backend::HttpFallback {
            backend_name,
            url,
        } => {
            assert_eq!(backend_name, "cosmian");
            assert_eq!(url, "http://localhost:8081");
        }
        _ => panic!("Expected HttpFallback backend"),
    }
}

#[test]
fn test_backend_aws_kms() {
    let backend = helpers::Backend::new_aws_kms("alias/my-key");
    match backend {
        helpers::Backend::AwsKms { key_id } => {
            assert_eq!(key_id, "alias/my-key");
        }
        _ => panic!("Expected AwsKms backend"),
    }
}

#[test]
fn test_backend_vault() {
    let backend = helpers::Backend::new_vault("http://localhost:8200", "test-token");
    match backend {
        helpers::Backend::Vault { addr, token } => {
            assert_eq!(addr, "http://localhost:8200");
            assert_eq!(token, "test-token");
        }
        _ => panic!("Expected Vault backend"),
    }
}

// =============================================================================
// Backend Availability Tests
// =============================================================================

#[test]
fn test_check_backend_available_unknown() {
    let result = helpers::check_backend_available("unknown_backend");
    assert!(!result);
}

#[test]
fn test_check_backend_available_without_env() {
    // These should return false if environment variables are not set
    // We can't guarantee the env is clean, so just verify it doesn't panic
    let _ = helpers::check_backend_available("rustyvault");
    let _ = helpers::check_backend_available("age");
    let _ = helpers::check_backend_available("aws");
    let _ = helpers::check_backend_available("vault");
    let _ = helpers::check_backend_available("cosmian");
}

// =============================================================================
// Utility Function Tests
// =============================================================================

#[test]
fn test_encode_base64() {
    let encoded = helpers::encode_base64(b"hello world");
    assert_eq!(encoded, "aGVsbG8gd29ybGQ=");
}

#[test]
fn test_decode_base64() {
    let decoded = helpers::decode_base64("aGVsbG8gd29ybGQ=").unwrap();
    assert_eq!(decoded, b"hello world");
}

#[test]
fn test_decode_base64_invalid() {
    let result = helpers::decode_base64("not!valid!base64!");
    assert!(result.is_err());
}

// =============================================================================
// Age Key Generation Tests
// =============================================================================

#[test]
fn test_generate_age_key() {
    let result = helpers::generate_age_key();
    assert!(result.is_ok());

    let (secret, public) = result.unwrap();
    // Age public keys start with "age1"
    assert!(public.starts_with("age1"));
    // Secret should not be empty
    assert!(!secret.is_empty());
}

// =============================================================================
// Plugin Structure Tests
// =============================================================================

#[test]
fn test_plugin_version() {
    use crate::KmsPlugin;
    use nu_plugin::Plugin;

    let plugin = KmsPlugin;
    let version = plugin.version();
    assert!(!version.is_empty());
}

#[test]
fn test_plugin_commands() {
    use crate::KmsPlugin;
    use nu_plugin::Plugin;

    let plugin = KmsPlugin;
    let commands = plugin.commands();

    // Should have 5 commands
    assert_eq!(commands.len(), 5);
}

#[test]
fn test_encrypt_command_signature() {
    use crate::KmsEncrypt;
    use nu_plugin::SimplePluginCommand;

    let cmd = KmsEncrypt;
    assert_eq!(SimplePluginCommand::name(&cmd), "kms encrypt");
    assert!(!SimplePluginCommand::examples(&cmd).is_empty());
}

#[test]
fn test_decrypt_command_signature() {
    use crate::KmsDecrypt;
    use nu_plugin::SimplePluginCommand;

    let cmd = KmsDecrypt;
    assert_eq!(SimplePluginCommand::name(&cmd), "kms decrypt");
    assert!(!SimplePluginCommand::examples(&cmd).is_empty());
}

#[test]
fn test_generate_key_command_signature() {
    use crate::KmsGenerateKey;
    use nu_plugin::SimplePluginCommand;

    let cmd = KmsGenerateKey;
    assert_eq!(SimplePluginCommand::name(&cmd), "kms generate-key");
    assert!(!SimplePluginCommand::examples(&cmd).is_empty());
}

#[test]
fn test_status_command_signature() {
    use crate::KmsStatus;
    use nu_plugin::SimplePluginCommand;

    let cmd = KmsStatus;
    assert_eq!(SimplePluginCommand::name(&cmd), "kms status");
    assert!(!SimplePluginCommand::examples(&cmd).is_empty());
}

#[test]
fn test_list_backends_command_signature() {
    use crate::KmsListBackends;
    use nu_plugin::SimplePluginCommand;

    let cmd = KmsListBackends;
    assert_eq!(SimplePluginCommand::name(&cmd), "kms list-backends");
    assert!(!SimplePluginCommand::examples(&cmd).is_empty());
}
