//! Integration tests for RedisService
//!
//! These tests verify that the RedisService correctly handles Redis connections
//! and operations. Some tests require a running Redis instance.

mod common;

use mecha10_cli::services::RedisService;
use std::time::Duration;

#[test]
fn test_service_creation_with_valid_url() {
    let service = RedisService::new("redis://localhost:6379");
    assert!(service.is_ok());
}

#[test]
fn test_service_url_accessor() {
    let service = RedisService::new("redis://localhost:6379").unwrap();
    assert_eq!(service.url(), "redis://localhost:6379");
}

#[test]
fn test_from_env_without_env_vars() {
    // Clear env vars to test default
    std::env::remove_var("MECHA10_REDIS_URL");
    std::env::remove_var("REDIS_URL");

    let service = RedisService::from_env();
    assert!(service.is_ok());
    // Should fall back to default
    assert_eq!(service.unwrap().url(), "redis://localhost:6379");
}

#[test]
fn test_from_env_with_mecha10_redis_url() {
    std::env::set_var("MECHA10_REDIS_URL", "redis://custom:1234");

    let service = RedisService::from_env().unwrap();
    assert_eq!(service.url(), "redis://custom:1234");

    std::env::remove_var("MECHA10_REDIS_URL");
}

#[test]
fn test_from_env_with_redis_url_fallback() {
    std::env::remove_var("MECHA10_REDIS_URL");
    std::env::set_var("REDIS_URL", "redis://fallback:5678");

    let service = RedisService::from_env().unwrap();
    assert_eq!(service.url(), "redis://fallback:5678");

    std::env::remove_var("REDIS_URL");
}

#[test]
fn test_from_env_precedence() {
    // MECHA10_REDIS_URL should take precedence over REDIS_URL
    std::env::set_var("MECHA10_REDIS_URL", "redis://primary:1111");
    std::env::set_var("REDIS_URL", "redis://secondary:2222");

    let service = RedisService::from_env().unwrap();
    assert_eq!(service.url(), "redis://primary:1111");

    std::env::remove_var("MECHA10_REDIS_URL");
    std::env::remove_var("REDIS_URL");
}

#[test]
fn test_default_service() {
    // Default should use from_env logic
    std::env::remove_var("MECHA10_REDIS_URL");
    std::env::remove_var("REDIS_URL");

    let service = RedisService::default();
    assert_eq!(service.url(), "redis://localhost:6379");
}

#[tokio::test]
async fn test_health_check_with_invalid_url() {
    // Service with unreachable Redis instance
    let service = RedisService::new("redis://localhost:9999").unwrap();

    // Health check should fail quickly
    let healthy = service.check_health(Duration::from_millis(500)).await;
    assert!(!healthy);
}

#[tokio::test]
async fn test_is_healthy_with_invalid_url() {
    // is_healthy is a convenience wrapper around check_health
    let service = RedisService::new("redis://localhost:9999").unwrap();
    let healthy = service.is_healthy().await;
    assert!(!healthy);
}

// The following tests require a running Redis instance
// They are ignored by default and can be run with: cargo test -- --ignored

#[tokio::test]
#[ignore]
async fn test_get_connection_with_running_redis() {
    let service = RedisService::new("redis://localhost:6379").unwrap();
    let result = service.get_connection().await;
    assert!(result.is_ok(), "Failed to connect to Redis: {:?}", result.err());
}

#[tokio::test]
#[ignore]
async fn test_get_multiplexed_connection_with_running_redis() {
    let service = RedisService::new("redis://localhost:6379").unwrap();
    let result = service.get_multiplexed_connection().await;
    assert!(
        result.is_ok(),
        "Failed to get multiplexed connection: {:?}",
        result.err()
    );
}

#[tokio::test]
#[ignore]
async fn test_health_check_with_running_redis() {
    let service = RedisService::new("redis://localhost:6379").unwrap();
    let healthy = service.check_health(Duration::from_secs(2)).await;
    assert!(healthy, "Redis health check failed");
}

#[tokio::test]
#[ignore]
async fn test_health_check_timeout() {
    // This test would need a Redis instance that's slow to respond
    // For now, we'll just verify the timeout mechanism doesn't panic
    let service = RedisService::new("redis://localhost:6379").unwrap();
    let _healthy = service.check_health(Duration::from_nanos(1)).await;
    // The result doesn't matter - we're testing that timeout works
}

#[tokio::test]
#[ignore]
async fn test_multiple_connections() {
    // Verify we can create multiple connections
    let service = RedisService::new("redis://localhost:6379").unwrap();

    let conn1 = service.get_connection().await;
    let conn2 = service.get_connection().await;

    assert!(conn1.is_ok());
    assert!(conn2.is_ok());
}
