//! Infrastructure Health Smoke Tests
//!
//! Tests to validate that core infrastructure services are available and functional.
//! These tests run first to ensure the foundation is solid before testing application services.

use super::common::*;

#[tokio::test]
async fn test_postgres_connection() {
    let result = with_timeout(async {
        let pool = sqlx::PgPool::connect(&database_url())
            .await
            .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        // Verify database is responsive
        let row: (i32,) = sqlx::query_as("SELECT 1")
            .fetch_one(&pool)
            .await
            .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        assert_eq!(row.0, 1, "Database query returned unexpected value");

        // Check TimescaleDB extension
        let has_timescale: (bool,) = sqlx::query_as(
            "SELECT COUNT(*) > 0 FROM pg_extension WHERE extname = 'timescaledb'"
        )
        .fetch_one(&pool)
        .await
        .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        pool.close().await;

        println!("✅ PostgreSQL connection successful (TimescaleDB: {})", has_timescale.0);
        Ok(())
    }).await;

    skip_if_unavailable!("PostgreSQL", { result });
}

#[tokio::test]
async fn test_postgres_schema_exists() {
    let result = with_timeout(async {
        let pool = sqlx::PgPool::connect(&database_url())
            .await
            .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        // Check for key tables
        let tables = vec!["orders", "positions", "market_data", "audit_log"];
        for table in tables {
            let exists: (bool,) = sqlx::query_as(
                "SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_name = $1)"
            )
            .bind(table)
            .fetch_one(&pool)
            .await
            .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

            assert!(exists.0, "Table '{}' does not exist", table);
            println!("  ✓ Table '{}' exists", table);
        }

        pool.close().await;
        println!("✅ PostgreSQL schema validation successful");
        Ok(())
    }).await;

    skip_if_unavailable!("PostgreSQL", { result });
}

#[tokio::test]
async fn test_redis_connection() {
    let result = with_timeout(async {
        use redis::AsyncCommands;

        let client = redis::Client::open(redis_url().as_str())
            .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        let mut con = client.get_multiplexed_async_connection()
            .await
            .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        // Test PING
        let pong: String = redis::cmd("PING")
            .query_async(&mut con)
            .await
            .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        assert_eq!(pong, "PONG", "Redis PING returned unexpected value");

        // Test SET/GET
        let test_key = "smoke_test:redis_health";
        let test_value = "healthy";

        con.set::<_, _, ()>(test_key, test_value)
            .await
            .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        let retrieved: String = con.get(test_key)
            .await
            .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        assert_eq!(retrieved, test_value, "Redis GET returned unexpected value");

        // Cleanup
        con.del::<_, ()>(test_key)
            .await
            .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        println!("✅ Redis connection and operations successful");
        Ok(())
    }).await;

    skip_if_unavailable!("Redis", { result });
}

#[tokio::test]
async fn test_vault_connectivity() {
    let result = with_timeout(async {
        let client = reqwest::Client::new();
        let vault_url = vault_url();

        // Test Vault health endpoint
        let response = client
            .get(format!("{}/v1/sys/health", vault_url))
            .send()
            .await
            .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        // Vault health returns 200 (initialized and unsealed), 429 (unsealed and standby),
        // 472 (data recovery mode), 473 (performance standby), or 501 (not initialized)
        let status = response.status();
        assert!(
            status == 200 || status == 429 || status == 473,
            "Vault health check returned unexpected status: {}",
            status
        );

        println!("✅ Vault connectivity successful (status: {})", status);
        Ok(())
    }).await;

    skip_if_unavailable!("Vault", { result });
}

#[tokio::test]
async fn test_influxdb_connectivity() {
    let result = with_timeout(async {
        let client = reqwest::Client::new();
        let influxdb_url = influxdb_url();

        // Test InfluxDB ping endpoint
        let response = client
            .get(format!("{}/ping", influxdb_url))
            .send()
            .await
            .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        assert!(
            response.status().is_success(),
            "InfluxDB ping failed with status: {}",
            response.status()
        );

        println!("✅ InfluxDB connectivity successful");
        Ok(())
    }).await;

    skip_if_unavailable!("InfluxDB", { result });
}

#[tokio::test]
async fn test_prometheus_connectivity() {
    let result = with_timeout(async {
        let client = reqwest::Client::new();
        let prometheus_url = prometheus_url();

        // Test Prometheus health endpoint
        let response = client
            .get(format!("{}/-/healthy", prometheus_url))
            .send()
            .await
            .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        assert!(
            response.status().is_success(),
            "Prometheus health check failed with status: {}",
            response.status()
        );

        println!("✅ Prometheus connectivity successful");
        Ok(())
    }).await;

    skip_if_unavailable!("Prometheus", { result });
}

#[tokio::test]
async fn test_grafana_connectivity() {
    let result = with_timeout(async {
        let client = reqwest::Client::new();
        let grafana_url = grafana_url();

        // Test Grafana API health endpoint
        let response = client
            .get(format!("{}/api/health", grafana_url))
            .send()
            .await
            .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;

        assert!(
            response.status().is_success(),
            "Grafana health check failed with status: {}",
            response.status()
        );

        println!("✅ Grafana connectivity successful");
        Ok(())
    }).await;

    skip_if_unavailable!("Grafana", { result });
}

#[tokio::test]
async fn test_infrastructure_all_healthy() {
    println!("🏥 Running comprehensive infrastructure health check...");

    let mut checks_passed = 0;
    let mut checks_failed = 0;

    // PostgreSQL
    match sqlx::PgPool::connect(&database_url()).await {
        Ok(pool) => {
            pool.close().await;
            println!("  ✓ PostgreSQL");
            checks_passed += 1;
        }
        Err(e) => {
            eprintln!("  ✗ PostgreSQL: {}", e);
            checks_failed += 1;
        }
    }

    // Redis
    match redis::Client::open(redis_url().as_str()) {
        Ok(client) => {
            match client.get_multiplexed_async_connection().await {
                Ok(_) => {
                    println!("  ✓ Redis");
                    checks_passed += 1;
                }
                Err(e) => {
                    eprintln!("  ✗ Redis: {}", e);
                    checks_failed += 1;
                }
            }
        }
        Err(e) => {
            eprintln!("  ✗ Redis: {}", e);
            checks_failed += 1;
        }
    }

    // Vault (optional - don't fail if unavailable)
    let client = reqwest::Client::new();
    match client.get(format!("{}/v1/sys/health", vault_url())).send().await {
        Ok(response) if response.status() == 200 || response.status() == 429 => {
            println!("  ✓ Vault");
            checks_passed += 1;
        }
        _ => {
            println!("  ⚠ Vault (not critical)");
        }
    }

    // InfluxDB (optional - don't fail if unavailable)
    match client.get(format!("{}/ping", influxdb_url())).send().await {
        Ok(response) if response.status().is_success() => {
            println!("  ✓ InfluxDB");
            checks_passed += 1;
        }
        _ => {
            println!("  ⚠ InfluxDB (not critical)");
        }
    }

    println!("\n📊 Infrastructure Health Summary:");
    println!("   Passed: {}", checks_passed);
    println!("   Failed: {}", checks_failed);

    // Require at least PostgreSQL and Redis
    assert!(checks_passed >= 2, "Critical infrastructure services are down");
    println!("✅ Infrastructure health check complete");
}
