//! Cache configuration for trust registry.

#[cfg(feature = "json-schema")]
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use crate::error::LastIDError;

/// Trust registry cache configuration.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
#[serde(default)]
pub struct CacheConfig {
    /// Enable caching (default: true)
    #[serde(default = "default_cache_enabled")]
    pub enabled: bool,

    /// Cache TTL in seconds (default: 60)
    #[serde(default = "default_cache_ttl")]
    pub ttl_seconds: u64,

    /// Maximum cache entries (default: 1000)
    #[serde(default = "default_cache_max_entries")]
    pub max_entries: usize,
}

const fn default_cache_enabled() -> bool {
    true
}
const fn default_cache_ttl() -> u64 {
    60
}
const fn default_cache_max_entries() -> usize {
    1000
}

impl Default for CacheConfig {
    fn default() -> Self {
        Self {
            enabled: default_cache_enabled(),
            ttl_seconds: default_cache_ttl(),
            max_entries: default_cache_max_entries(),
        }
    }
}

impl CacheConfig {
    /// Create a disabled cache configuration.
    #[must_use]
    pub fn disabled() -> Self {
        Self {
            enabled: false,
            ..Default::default()
        }
    }

    /// Validate the cache configuration.
    pub fn validate(&self) -> Result<(), LastIDError> {
        if self.enabled {
            if self.ttl_seconds == 0 {
                return Err(LastIDError::config("cache ttl_seconds must be > 0"));
            }

            if self.ttl_seconds > 3600 {
                return Err(LastIDError::config(
                    "cache ttl_seconds must be <= 3600 (1 hour)",
                ));
            }

            if self.max_entries == 0 {
                return Err(LastIDError::config("cache max_entries must be > 0"));
            }
        }

        Ok(())
    }

    /// Merge another configuration into this one.
    pub const fn merge(&mut self, other: &Self) {
        if !other.enabled {
            self.enabled = false;
        }
        if other.ttl_seconds != default_cache_ttl() {
            self.ttl_seconds = other.ttl_seconds;
        }
        if other.max_entries != default_cache_max_entries() {
            self.max_entries = other.max_entries;
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_default_values() {
        let config = CacheConfig::default();
        assert!(config.enabled);
        assert_eq!(config.ttl_seconds, 60);
        assert_eq!(config.max_entries, 1000);
    }

    #[test]
    fn test_disabled() {
        let config = CacheConfig::disabled();
        assert!(!config.enabled);
    }

    #[test]
    fn test_validate_valid() {
        let config = CacheConfig::default();
        assert!(config.validate().is_ok());

        let disabled = CacheConfig::disabled();
        assert!(disabled.validate().is_ok());
    }

    #[test]
    fn test_validate_invalid_ttl() {
        let mut config = CacheConfig::default();
        config.ttl_seconds = 0;
        assert!(config.validate().is_err());

        config.ttl_seconds = 7200; // > 1 hour
        assert!(config.validate().is_err());
    }

    #[test]
    fn test_validate_invalid_max_entries() {
        let mut config = CacheConfig::default();
        config.max_entries = 0;
        assert!(config.validate().is_err());
    }
}
