//! Core KMS Types
//!
//! Defines the fundamental data structures used throughout the KMS system.

use std::collections::HashMap;

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use zeroize::ZeroizeOnDrop;

/// Key data structure with secure handling
#[derive(Debug, Clone, Serialize, Deserialize)]
// TODO: Re-enable Zeroize once trait bounds are satisfied
pub struct KeyData {
    /// Unique key identifier
    pub key_id: String,
    /// Key type (symmetric, asymmetric, etc.)
    pub key_type: KeyType,
    /// Key algorithm
    pub algorithm: KeyAlgorithm,
    /// Key usage permissions
    pub usage: KeyUsage,
    /// Key size in bits
    pub key_size: u32,
    /// Actual key material (encrypted at rest)
    // TODO: Re-enable #[zeroize(skip)] once Zeroize derive is enabled
    pub key_material: SecretBytes,
    /// Key metadata
    pub metadata: KeyMetadata,
    /// Creation timestamp
    pub created_at: DateTime<Utc>,
    /// Last access timestamp
    pub last_accessed: Option<DateTime<Utc>>,
    /// Expiration timestamp
    pub expires_at: Option<DateTime<Utc>>,
    /// Key status
    pub status: KeyStatus,
    /// Associated tags
    pub tags: HashMap<String, String>,
}

/// Secure byte container that zeroes on drop
#[derive(Debug, Clone, Serialize, Deserialize, ZeroizeOnDrop)]
pub struct SecretBytes(#[zeroize(skip)] pub Vec<u8>);

impl SecretBytes {
    pub fn new(data: Vec<u8>) -> Self {
        Self(data)
    }

    pub fn as_slice(&self) -> &[u8] {
        &self.0
    }

    pub fn len(&self) -> usize {
        self.0.len()
    }

    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }
}

/// Key type enumeration
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum KeyType {
    /// Symmetric encryption key
    Symmetric,
    /// Asymmetric key pair
    Asymmetric,
    /// HMAC key
    Hmac,
    /// Key derivation key
    Kdf,
    /// Data encryption key
    Dek,
    /// Key encryption key
    Kek,
}

/// Key algorithm enumeration
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum KeyAlgorithm {
    /// AES-256-GCM
    Aes256Gcm,
    /// AES-128-GCM
    Aes128Gcm,
    /// ChaCha20Poly1305
    ChaCha20Poly1305,
    /// RSA-2048
    Rsa2048,
    /// RSA-4096
    Rsa4096,
    /// ECDSA P-256
    EcdsaP256,
    /// ECDSA P-384
    EcdsaP384,
    /// Ed25519
    Ed25519,
    /// HMAC-SHA256
    HmacSha256,
    /// HMAC-SHA512
    HmacSha512,
    /// HKDF-SHA256
    HkdfSha256,
}

/// Key usage flags
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct KeyUsage {
    pub encrypt: bool,
    pub decrypt: bool,
    pub sign: bool,
    pub verify: bool,
    pub wrap: bool,
    pub unwrap: bool,
    pub derive: bool,
    pub export: bool,
}

impl Default for KeyUsage {
    fn default() -> Self {
        Self {
            encrypt: true,
            decrypt: true,
            sign: false,
            verify: false,
            wrap: false,
            unwrap: false,
            derive: false,
            export: false,
        }
    }
}

/// Key metadata
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct KeyMetadata {
    /// Human-readable name
    pub name: Option<String>,
    /// Description
    pub description: Option<String>,
    /// Owner/creator
    pub owner: Option<String>,
    /// Application/service using this key
    pub application: Option<String>,
    /// Environment (dev, test, prod)
    pub environment: Option<String>,
    /// Version number
    pub version: u32,
    /// Custom metadata
    pub custom: HashMap<String, String>,
}

impl Default for KeyMetadata {
    fn default() -> Self {
        Self {
            name: None,
            description: None,
            owner: None,
            application: None,
            environment: None,
            version: 1,
            custom: HashMap::new(),
        }
    }
}

/// Key status enumeration
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum KeyStatus {
    /// Key is active and can be used
    Active,
    /// Key is pending activation
    Pending,
    /// Key is deactivated but not destroyed
    Deactivated,
    /// Key is compromised and should not be used
    Compromised,
    /// Key is destroyed and cannot be recovered
    Destroyed,
    /// Key is archived for compliance but not active
    Archived,
}

/// KMS operation mode
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum KmsMode {
    /// Local SQLite storage only
    Local,
    /// Remote Cosmian KMS only
    Remote,
    /// Hybrid with local cache and remote fallback
    Hybrid,
}

/// Provider credentials for cloud services
// TODO: Re-enable ZeroizeOnDrop once trait bounds are satisfied for all fields
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProviderCredentials {
    /// Provider name (aws, upcloud, etc.)
    pub provider: String,
    /// Credential type
    pub credential_type: CredentialType,
    /// Access key ID or username
    pub access_key: String,
    /// Secret access key or password
    // TODO: Re-enable #[zeroize(skip)] once ZeroizeOnDrop is re-enabled
    pub secret_key: SecretBytes,
    /// Session token (for temporary credentials)
    // TODO: Re-enable #[zeroize(skip)] once ZeroizeOnDrop is re-enabled
    pub session_token: Option<SecretBytes>,
    /// Region or endpoint
    pub region: Option<String>,
    /// Additional configuration
    pub config: HashMap<String, String>,
    /// Expiration time
    pub expires_at: Option<DateTime<Utc>>,
    /// Creation time
    pub created_at: DateTime<Utc>,
}

/// Credential type enumeration
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum CredentialType {
    /// Long-term access keys
    AccessKey,
    /// Temporary session credentials
    SessionToken,
    /// API token
    ApiToken,
    /// Certificate-based authentication
    Certificate,
    /// OAuth token
    OAuth,
}

/// Health status for KMS components
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HealthStatus {
    pub healthy: bool,
    pub message: String,
    pub last_check: DateTime<Utc>,
    pub metrics: HashMap<String, f64>,
}

impl HealthStatus {
    pub fn healthy(message: impl Into<String>) -> Self {
        Self {
            healthy: true,
            message: message.into(),
            last_check: Utc::now(),
            metrics: HashMap::new(),
        }
    }

    pub fn unhealthy(message: impl Into<String>) -> Self {
        Self {
            healthy: false,
            message: message.into(),
            last_check: Utc::now(),
            metrics: HashMap::new(),
        }
    }

    pub fn is_healthy(&self) -> bool {
        self.healthy
    }

    pub fn with_metrics(mut self, metrics: HashMap<String, f64>) -> Self {
        self.metrics = metrics;
        self
    }
}

/// Overall KMS health status
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct KmsHealthStatus {
    pub backend: HealthStatus,
    pub rotation: HealthStatus,
    pub credentials: HealthStatus,
    pub overall: bool,
}

/// Key rotation policy
#[derive(Debug, Clone, Serialize, Deserialize, validator::Validate)]
pub struct RotationPolicy {
    /// Enable automatic rotation
    pub enabled: bool,
    /// Rotation interval in seconds
    pub interval_seconds: u64,
    /// Maximum key age before forced rotation
    pub max_age_seconds: u64,
    /// Advance notice for rotation (seconds)
    pub notice_seconds: u64,
    /// Keys to exclude from rotation
    pub exclude_keys: Vec<String>,
    /// Rotation schedule (cron expression)
    pub schedule: Option<String>,
}

impl Default for RotationPolicy {
    fn default() -> Self {
        Self {
            enabled: false,
            interval_seconds: 30 * 24 * 3600, // 30 days
            max_age_seconds: 90 * 24 * 3600,  // 90 days
            notice_seconds: 7 * 24 * 3600,    // 7 days
            exclude_keys: Vec::new(),
            schedule: None,
        }
    }
}

/// Cache configuration
#[derive(Debug, Clone, Serialize, Deserialize, validator::Validate)]
pub struct CacheConfig {
    /// Enable caching
    pub enabled: bool,
    /// Cache backend type
    pub backend: CacheBackend,
    /// Default TTL in seconds
    pub default_ttl_seconds: u64,
    /// Maximum cache size in bytes
    pub max_size_bytes: u64,
    /// Redis connection URL (if using Redis)
    pub redis_url: Option<String>,
    /// Local cache directory (if using local)
    pub local_dir: Option<String>,
}

/// Cache backend type
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum CacheBackend {
    /// In-memory cache
    Memory,
    /// Redis cache
    Redis,
    /// Local file cache
    Local,
}

/// HSM configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HsmConfig {
    /// Enable HSM support
    pub enabled: bool,
    /// HSM type
    pub hsm_type: HsmType,
    /// PKCS#11 library path
    pub pkcs11_library: Option<String>,
    /// Slot ID
    pub slot_id: Option<u64>,
    /// Token label
    pub token_label: Option<String>,
    /// PIN or password
    #[serde(skip)]
    pub pin: Option<SecretBytes>,
}

impl Default for HsmConfig {
    fn default() -> Self {
        Self {
            enabled: false,
            hsm_type: HsmType::Pkcs11,
            pkcs11_library: None,
            slot_id: None,
            token_label: None,
            pin: None,
        }
    }
}

/// HSM type enumeration
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum HsmType {
    /// Generic PKCS#11 HSM
    Pkcs11,
    /// YubiHSM 2
    YubiHsm,
    /// AWS CloudHSM
    CloudHsm,
    /// Azure Dedicated HSM
    AzureHsm,
}

/// Zero-knowledge proof configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ZkpConfig {
    /// Enable ZKP features
    pub enabled: bool,
    /// Proof system type
    pub proof_system: ZkpSystem,
    /// Trusted setup parameters path
    pub setup_params_path: Option<String>,
    /// Verification key path
    pub verification_key_path: Option<String>,
}

impl Default for ZkpConfig {
    fn default() -> Self {
        Self {
            enabled: false,
            proof_system: ZkpSystem::Groth16,
            setup_params_path: None,
            verification_key_path: None,
        }
    }
}

/// Zero-knowledge proof system type
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ZkpSystem {
    /// Groth16 proof system
    Groth16,
    /// PLONK proof system
    Plonk,
    /// Bulletproofs
    Bulletproofs,
}

/// Audit event types
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AuditEventType {
    KeyAccessed,
    KeyStored,
    KeyDeleted,
    KeyRotated,
    CredentialsAccessed,
    CredentialsStored,
    SystemInitialized,
    SystemShutdown,
    HealthCheck,
    Error,
}

/// Audit event data
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuditEvent {
    pub event_id: Uuid,
    pub event_type: AuditEventType,
    pub timestamp: DateTime<Utc>,
    pub resource_id: Option<String>,
    pub user_id: Option<String>,
    pub source_ip: Option<String>,
    pub user_agent: Option<String>,
    pub success: bool,
    pub message: String,
    pub metadata: HashMap<String, serde_json::Value>,
    /// Action performed (e.g., "encrypt", "decrypt", "rotate")
    pub action: String,
    /// Result of the action (e.g., "success", "failure")
    pub result: String,
    /// IP address of the requester (alias for source_ip for compatibility)
    pub ip_address: Option<String>,
    /// Additional details as JSON value
    pub details: serde_json::Value,
}

impl AuditEvent {
    pub fn key_accessed(key_id: &str) -> Self {
        Self {
            event_id: Uuid::new_v4(),
            event_type: AuditEventType::KeyAccessed,
            timestamp: Utc::now(),
            resource_id: Some(key_id.to_string()),
            user_id: None,
            source_ip: None,
            user_agent: None,
            success: true,
            message: format!("Key {} accessed successfully", key_id),
            metadata: HashMap::new(),
            action: "access".to_string(),
            result: "success".to_string(),
            ip_address: None,
            details: serde_json::json!({}),
        }
    }

    pub fn key_stored(key_id: &str) -> Self {
        Self {
            event_id: Uuid::new_v4(),
            event_type: AuditEventType::KeyStored,
            timestamp: Utc::now(),
            resource_id: Some(key_id.to_string()),
            user_id: None,
            source_ip: None,
            user_agent: None,
            success: true,
            message: format!("Key {} stored successfully", key_id),
            metadata: HashMap::new(),
            action: "store".to_string(),
            result: "success".to_string(),
            ip_address: None,
            details: serde_json::json!({}),
        }
    }

    pub fn key_deleted(key_id: &str) -> Self {
        Self {
            event_id: Uuid::new_v4(),
            event_type: AuditEventType::KeyDeleted,
            timestamp: Utc::now(),
            resource_id: Some(key_id.to_string()),
            user_id: None,
            source_ip: None,
            user_agent: None,
            success: true,
            message: format!("Key {} deleted successfully", key_id),
            metadata: HashMap::new(),
            action: "delete".to_string(),
            result: "success".to_string(),
            ip_address: None,
            details: serde_json::json!({}),
        }
    }

    pub fn key_not_found(key_id: &str) -> Self {
        Self {
            event_id: Uuid::new_v4(),
            event_type: AuditEventType::KeyAccessed,
            timestamp: Utc::now(),
            resource_id: Some(key_id.to_string()),
            user_id: None,
            source_ip: None,
            user_agent: None,
            success: false,
            message: format!("Key {} not found", key_id),
            metadata: HashMap::new(),
            action: "access".to_string(),
            result: "failure".to_string(),
            ip_address: None,
            details: serde_json::json!({"error": "not_found"}),
        }
    }

    pub fn key_access_failed(key_id: &str, error: &crate::kms::error::KmsError) -> Self {
        Self {
            event_id: Uuid::new_v4(),
            event_type: AuditEventType::Error,
            timestamp: Utc::now(),
            resource_id: Some(key_id.to_string()),
            user_id: None,
            source_ip: None,
            user_agent: None,
            success: false,
            message: format!("Failed to access key {}: {}", key_id, error),
            metadata: HashMap::new(),
            action: "access".to_string(),
            result: "failure".to_string(),
            ip_address: None,
            details: serde_json::json!({"error": error.to_string()}),
        }
    }

    pub fn key_store_failed(key_id: &str, error: &crate::kms::error::KmsError) -> Self {
        Self {
            event_id: Uuid::new_v4(),
            event_type: AuditEventType::Error,
            timestamp: Utc::now(),
            resource_id: Some(key_id.to_string()),
            user_id: None,
            source_ip: None,
            user_agent: None,
            success: false,
            message: format!("Failed to store key {}: {}", key_id, error),
            metadata: HashMap::new(),
            action: "store".to_string(),
            result: "failure".to_string(),
            ip_address: None,
            details: serde_json::json!({"error": error.to_string()}),
        }
    }

    pub fn key_delete_failed(key_id: &str, error: &crate::kms::error::KmsError) -> Self {
        Self {
            event_id: Uuid::new_v4(),
            event_type: AuditEventType::Error,
            timestamp: Utc::now(),
            resource_id: Some(key_id.to_string()),
            user_id: None,
            source_ip: None,
            user_agent: None,
            success: false,
            message: format!("Failed to delete key {}: {}", key_id, error),
            metadata: HashMap::new(),
            action: "delete".to_string(),
            result: "failure".to_string(),
            ip_address: None,
            details: serde_json::json!({"error": error.to_string()}),
        }
    }

    pub fn key_delete_failed_not_found(key_id: &str) -> Self {
        Self {
            event_id: Uuid::new_v4(),
            event_type: AuditEventType::KeyDeleted,
            timestamp: Utc::now(),
            resource_id: Some(key_id.to_string()),
            user_id: None,
            source_ip: None,
            user_agent: None,
            success: false,
            message: format!("Key {} not found for deletion", key_id),
            metadata: HashMap::new(),
            action: "delete".to_string(),
            result: "failure".to_string(),
            ip_address: None,
            details: serde_json::json!({"error": "not_found"}),
        }
    }

    pub fn system_initialized() -> Self {
        Self {
            event_id: Uuid::new_v4(),
            event_type: AuditEventType::SystemInitialized,
            timestamp: Utc::now(),
            resource_id: None,
            user_id: None,
            source_ip: None,
            user_agent: None,
            success: true,
            message: "KMS system initialized successfully".to_string(),
            metadata: HashMap::new(),
            action: "initialize".to_string(),
            result: "success".to_string(),
            ip_address: None,
            details: serde_json::json!({}),
        }
    }

    pub fn system_shutdown() -> Self {
        Self {
            event_id: Uuid::new_v4(),
            event_type: AuditEventType::SystemShutdown,
            timestamp: Utc::now(),
            resource_id: None,
            user_id: None,
            source_ip: None,
            user_agent: None,
            success: true,
            message: "KMS system shutdown successfully".to_string(),
            metadata: HashMap::new(),
            action: "shutdown".to_string(),
            result: "success".to_string(),
            ip_address: None,
            details: serde_json::json!({}),
        }
    }

    pub fn key_operation(operation: &str, key_id: &str) -> Self {
        Self {
            event_id: Uuid::new_v4(),
            event_type: AuditEventType::KeyAccessed,
            timestamp: Utc::now(),
            resource_id: Some(key_id.to_string()),
            user_id: None,
            source_ip: None,
            user_agent: None,
            success: true,
            message: format!(
                "Key {} operation '{}' completed successfully",
                key_id, operation
            ),
            metadata: HashMap::new(),
            action: operation.to_string(),
            result: "success".to_string(),
            ip_address: None,
            details: serde_json::json!({}),
        }
    }

    pub fn key_operation_failed(
        operation: &str,
        key_id: &str,
        error: &crate::kms::error::KmsError,
    ) -> Self {
        Self {
            event_id: Uuid::new_v4(),
            event_type: AuditEventType::Error,
            timestamp: Utc::now(),
            resource_id: Some(key_id.to_string()),
            user_id: None,
            source_ip: None,
            user_agent: None,
            success: false,
            message: format!("Key {} operation '{}' failed: {}", key_id, operation, error),
            metadata: HashMap::new(),
            action: operation.to_string(),
            result: "failure".to_string(),
            ip_address: None,
            details: serde_json::json!({"error": error.to_string()}),
        }
    }

    pub fn key_generated(key_id: &str) -> Self {
        Self {
            event_id: Uuid::new_v4(),
            event_type: AuditEventType::KeyAccessed,
            timestamp: Utc::now(),
            resource_id: Some(key_id.to_string()),
            user_id: None,
            source_ip: None,
            user_agent: None,
            success: true,
            message: format!("Key {} generated successfully", key_id),
            metadata: HashMap::new(),
            action: "generate".to_string(),
            result: "success".to_string(),
            ip_address: None,
            details: serde_json::json!({}),
        }
    }

    pub fn key_rotated(key_id: &str, new_key_id: &str) -> Self {
        Self {
            event_id: Uuid::new_v4(),
            event_type: AuditEventType::KeyAccessed,
            timestamp: Utc::now(),
            resource_id: Some(key_id.to_string()),
            user_id: None,
            source_ip: None,
            user_agent: None,
            success: true,
            message: format!("Key {} rotated successfully to {}", key_id, new_key_id),
            metadata: HashMap::new(),
            action: "rotate".to_string(),
            result: "success".to_string(),
            ip_address: None,
            details: serde_json::json!({"new_key_id": new_key_id}),
        }
    }

    pub fn key_exported(key_id: &str, wrap_key_id: &str) -> Self {
        Self {
            event_id: Uuid::new_v4(),
            event_type: AuditEventType::KeyAccessed,
            timestamp: Utc::now(),
            resource_id: Some(key_id.to_string()),
            user_id: None,
            source_ip: None,
            user_agent: None,
            success: true,
            message: format!(
                "Key {} exported successfully with wrapping key {}",
                key_id, wrap_key_id
            ),
            metadata: HashMap::new(),
            action: "export".to_string(),
            result: "success".to_string(),
            ip_address: None,
            details: serde_json::json!({"wrap_key_id": wrap_key_id}),
        }
    }

    pub fn key_imported(key_id: &str) -> Self {
        Self {
            event_id: Uuid::new_v4(),
            event_type: AuditEventType::KeyAccessed,
            timestamp: Utc::now(),
            resource_id: Some(key_id.to_string()),
            user_id: None,
            source_ip: None,
            user_agent: None,
            success: true,
            message: format!("Key {} imported successfully", key_id),
            metadata: HashMap::new(),
            action: "import".to_string(),
            result: "success".to_string(),
            ip_address: None,
            details: serde_json::json!({}),
        }
    }
}

/// Key rotation status
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RotationStatus {
    pub key_id: String,
    pub current_version: u32,
    pub next_rotation: Option<DateTime<Utc>>,
    pub last_rotation: Option<DateTime<Utc>>,
    pub rotation_policy: String,
    pub status: RotationState,
    pub failure_count: u32,
    pub last_error: Option<String>,
}

/// Rotation state enumeration
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum RotationState {
    Scheduled,
    InProgress,
    Completed,
    Failed,
    Disabled,
}

/// HSM key specification
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HsmKeySpec {
    pub key_type: HsmKeyType,
    pub algorithm: String,
    pub key_size: u32,
    pub usage: KeyUsage,
    pub extractable: bool,
    pub attributes: HashMap<String, String>,
}

/// HSM key type
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum HsmKeyType {
    Symmetric,
    PublicKey,
    PrivateKey,
    SecretKey,
}

/// HSM information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HsmInfo {
    pub manufacturer: String,
    pub model: String,
    pub serial_number: String,
    pub firmware_version: String,
    pub slot_count: u32,
    pub available_mechanisms: Vec<String>,
    pub max_session_count: u32,
    pub current_session_count: u32,
}

/// Migration result
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MigrationResult {
    pub migration_id: String,
    pub total_keys: u32,
    pub migrated_keys: u32,
    pub failed_keys: u32,
    pub start_time: DateTime<Utc>,
    pub end_time: Option<DateTime<Utc>>,
    pub status: MigrationStatus,
    pub errors: Vec<String>,
}

/// Migration verification result
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MigrationVerification {
    pub migration_id: String,
    pub verified_keys: u32,
    pub failed_verifications: u32,
    pub integrity_check_passed: bool,
    pub verification_time: DateTime<Utc>,
    pub discrepancies: Vec<String>,
}

/// Migration status
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum MigrationStatus {
    Pending,
    InProgress,
    Completed,
    Failed,
    RolledBack,
}

impl Default for HsmKeySpec {
    fn default() -> Self {
        Self {
            key_type: HsmKeyType::Symmetric,
            algorithm: "AES".to_string(),
            key_size: 256,
            usage: KeyUsage::default(),
            extractable: false,
            attributes: HashMap::new(),
        }
    }
}
