use std::time::Duration;

use crate::{
    cache_redis::{RedisBreakerConfig, RedisCacheConfig},
    lock::{LockError, LockResult},
};

/// Redis distributed lock configuration.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RedisLockConfig {
    /// Redis connection and command settings.
    pub redis: RedisCacheConfig,
    /// Namespace prefix for lock keys.
    pub namespace: String,
    /// Timeout for acquire and release commands.
    pub command_timeout: Duration,
    /// Optional circuit breaker protecting lock operations.
    pub breaker: RedisBreakerConfig,
    /// Whether Redis Cluster lock keys must contain a non-empty hash tag.
    pub require_cluster_hash_tag: bool,
}

impl Default for RedisLockConfig {
    fn default() -> Self {
        Self {
            redis: RedisCacheConfig::default(),
            namespace: "rs-zero:lock".to_string(),
            command_timeout: Duration::from_secs(2),
            breaker: RedisBreakerConfig::default(),
            require_cluster_hash_tag: true,
        }
    }
}

impl RedisLockConfig {
    /// Returns production-oriented Redis lock defaults.
    pub fn go_zero_defaults() -> Self {
        Self {
            breaker: RedisBreakerConfig::go_zero_defaults(),
            ..Self::default()
        }
    }

    /// Validates configuration values that can be checked locally.
    pub fn validate(&self) -> LockResult<()> {
        self.redis.validate()?;
        if self.namespace.trim().is_empty() {
            return Err(LockError::InvalidConfig(
                "redis lock namespace is required".to_string(),
            ));
        }
        if self.command_timeout.is_zero() {
            return Err(LockError::InvalidConfig(
                "redis lock command_timeout must be greater than zero".to_string(),
            ));
        }
        Ok(())
    }
}
