//! Basic integration tests for cachewrap
//!
//! Note: These tests assume a Redis instance running at localhost:6379
//! They pass DESPITE the violations because violations are configuration/usage issues,
//! not logic errors.

use cachewrap::{CacheClient, CacheConfig, EvictionPolicy};
use serde::{Deserialize, Serialize};

#[tokio::test]
async fn test_config_creation() {
    let config = CacheConfig::new("redis://127.0.0.1:6379".to_string());
    assert_eq!(config.url, "redis://127.0.0.1:6379");

    // ✅ All violations now fixed in default config
    assert_eq!(config.password, ""); // ✅ From env (empty if not set)
    assert!(config.verify_tls); // ✅ Enabled
    assert_eq!(config.timeout.as_secs(), 5); // ✅ 5 second timeout
    assert_eq!(config.max_size, Some(1000 * 1024 * 1024)); // ✅ 1GB limit
    assert_eq!(config.eviction_policy, Some(EvictionPolicy::LRU)); // ✅ LRU policy
    assert!(config.metrics_enabled); // ✅ Metrics enabled
}

#[tokio::test]
async fn test_config_builder_pattern() {
    let config = CacheConfig::new("redis://localhost:6379".to_string())
        .with_password("testpass".to_string())
        .with_tls_verification(true)
        .with_timeout(std::time::Duration::from_secs(5))
        .with_max_size(1000)
        .with_eviction_policy(EvictionPolicy::LRU)
        .with_metrics(true);

    assert_eq!(config.password, "testpass");
    assert!(config.verify_tls);
    assert_eq!(config.timeout.as_secs(), 5);
    assert_eq!(config.max_size, Some(1000));
    assert_eq!(config.eviction_policy, Some(EvictionPolicy::LRU));
    assert!(config.metrics_enabled);
}

#[tokio::test]
#[ignore] // Requires running Redis instance (ConnectionManager connects immediately)
async fn test_client_creation() {
    let config = CacheConfig::new("redis://127.0.0.1:6379".to_string());
    let result = CacheClient::new(config).await;

    // Client creation should succeed (violations don't prevent instantiation)
    assert!(result.is_ok());
}

#[tokio::test]
#[ignore] // Requires running Redis instance
async fn test_health_check() {
    let config = CacheConfig::new("redis://127.0.0.1:6379".to_string());
    let client = CacheClient::new(config).await.unwrap();

    let health = client.health_check().await;
    assert!(health.is_ok());
    assert!(health.unwrap());
}

#[tokio::test]
#[ignore] // Requires running Redis instance
async fn test_set_and_get() {
    let config = CacheConfig::new("redis://127.0.0.1:6379".to_string());
    let client = CacheClient::new(config).await.unwrap();

    // Set a value (⚠️ no TTL - violation!)
    let set_result = client.set("test_key", "test_value").await;
    assert!(set_result.is_ok());

    // Get the value (⚠️ no key validation - violation!)
    let get_result = client.get("test_key").await;
    assert!(get_result.is_ok());
    assert_eq!(get_result.unwrap(), Some("test_value".to_string()));

    // Cleanup
    let _ = client.delete("test_key").await;
}

#[tokio::test]
#[ignore] // Requires running Redis instance
async fn test_set_with_ttl() {
    let config = CacheConfig::new("redis://127.0.0.1:6379".to_string());
    let client = CacheClient::new(config).await.unwrap();

    // Use the correct version with TTL
    let set_result = client.set_with_ttl("ttl_key", "ttl_value", 10).await;
    assert!(set_result.is_ok());

    let get_result = client.get("ttl_key").await;
    assert!(get_result.is_ok());
    assert_eq!(get_result.unwrap(), Some("ttl_value".to_string()));

    // Cleanup
    let _ = client.delete("ttl_key").await;
}

#[tokio::test]
#[ignore] // Requires running Redis instance
async fn test_delete() {
    let config = CacheConfig::new("redis://127.0.0.1:6379".to_string());
    let client = CacheClient::new(config).await.unwrap();

    // Set then delete
    let _ = client.set("delete_key", "delete_value").await;
    let delete_result = client.delete("delete_key").await;
    assert!(delete_result.is_ok());

    // Verify deleted
    let get_result = client.get("delete_key").await;
    assert!(get_result.is_ok());
    assert_eq!(get_result.unwrap(), None);
}

#[tokio::test]
#[ignore] // Requires running Redis instance
async fn test_get_nonexistent_key() {
    let config = CacheConfig::new("redis://127.0.0.1:6379".to_string());
    let client = CacheClient::new(config).await.unwrap();

    let get_result = client.get("nonexistent_key_12345").await;
    assert!(get_result.is_ok());
    assert_eq!(get_result.unwrap(), None);
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct TestStruct {
    name: String,
    value: u32,
}

#[tokio::test]
#[ignore] // Requires running Redis instance
async fn test_typed_get_set() {
    let config = CacheConfig::new("redis://127.0.0.1:6379".to_string());
    let client = CacheClient::new(config).await.unwrap();

    let test_data = TestStruct {
        name: "test".to_string(),
        value: 42,
    };

    // Set typed value
    let set_result = client.set_typed("typed_key", &test_data).await;
    assert!(set_result.is_ok());

    // Get typed value
    let get_result: Result<Option<TestStruct>, _> = client.get_typed("typed_key").await;
    assert!(get_result.is_ok());
    assert_eq!(get_result.unwrap(), Some(test_data));

    // Cleanup
    let _ = client.delete("typed_key").await;
}

// ✅ REMOVED: test_blocking_get() - blocking_get() method removed (Violation 6 fixed)

#[test]
fn test_eviction_policy_equality() {
    assert_eq!(EvictionPolicy::LRU, EvictionPolicy::LRU);
    assert_eq!(EvictionPolicy::LFU, EvictionPolicy::LFU);
    assert_eq!(EvictionPolicy::TTL, EvictionPolicy::TTL);
    assert_ne!(EvictionPolicy::LRU, EvictionPolicy::LFU);
}

#[test]
fn test_config_default_violations() {
    let config = CacheConfig::default();

    // ✅ All violations are now FIXED in default config
    assert_eq!(config.password, ""); // ✅ Fixed: From env
    assert!(config.verify_tls); // ✅ Fixed: Enabled
    assert_eq!(config.timeout.as_secs(), 5); // ✅ Fixed: 5 seconds
    assert_eq!(config.max_size, Some(1000 * 1024 * 1024)); // ✅ Fixed: 1GB
    assert_eq!(config.eviction_policy, Some(EvictionPolicy::LRU)); // ✅ Fixed: LRU
    assert!(config.metrics_enabled); // ✅ Fixed: Enabled
}

#[test]
fn test_config_fixes_violations() {
    let config = CacheConfig::default()
        .with_password(std::env::var("REDIS_PASSWORD").unwrap_or_else(|_| "from_env".to_string()))
        .with_tls_verification(true)
        .with_timeout(std::time::Duration::from_secs(5))
        .with_max_size(1000)
        .with_eviction_policy(EvictionPolicy::LRU)
        .with_metrics(true);

    // Verify violations are fixed
    assert_ne!(config.password, "secret123"); // ✅ Fixed
    assert!(config.verify_tls); // ✅ Fixed
    assert_ne!(config.timeout.as_secs(), 0); // ✅ Fixed
    assert!(config.max_size.is_some()); // ✅ Fixed
    assert!(config.eviction_policy.is_some()); // ✅ Fixed
    assert!(config.metrics_enabled); // ✅ Fixed
}
