use actix_web::dev::ServiceResponse;
use actix_web::web::Data;
use actix_web::{App, test};
use athena_rs::api::health::ping;
use athena_rs::drivers::postgresql::sqlx_driver::PostgresClientRegistry;
use moka::future::Cache;
use reqwest::Client;
use serde_json::{Value, json};
use std::str;
use std::sync::Arc;
use std::time::{Duration, Instant};

use athena_rs::AppState;

#[actix_web::test]
async fn test_ping_endpoint() {
    let cache: Arc<Cache<String, Value>> = Arc::new(
        Cache::builder()
            .time_to_live(Duration::from_secs(60))
            .build(),
    );
    let immortal_cache: Arc<Cache<String, Value>> = Arc::new(Cache::builder().build());
    let client = Client::builder()
        .pool_idle_timeout(Duration::from_secs(90))
        .build()
        .expect("Failed to build HTTP client");

    let jdbc_pool_cache = Arc::new(Cache::builder().max_capacity(64).build());
    let app_state = AppState {
        cache,
        immortal_cache,
        client,
        process_start_time_seconds: 0,
        process_started_at: Instant::now(),
        pg_registry: Arc::new(PostgresClientRegistry::empty()),
        jdbc_pool_cache,
        gateway_force_camel_case_to_snake_case: false,
        gateway_auto_cast_uuid_filter_values_to_text: true,
        pipeline_registry: None,
        logging_client_name: None,
        gateway_auth_client_name: None,
        gateway_jdbc_allow_private_hosts: true,
        gateway_jdbc_allowed_hosts: vec![],
        prometheus_metrics_enabled: false,
        metrics_state: Arc::new(athena_rs::api::metrics::MetricsState::new()),
    };

    let app = test::init_service(App::new().app_data(Data::new(app_state)).service(ping)).await;
    let req = test::TestRequest::get().uri("/ping").to_request();
    let resp: ServiceResponse = test::call_service(&app, req).await;

    assert!(resp.status().is_success());

    let body = test::read_body(resp).await;
    assert_eq!(str::from_utf8(&body).unwrap(), "pong");
}

#[test]
async fn test_app_state_creation() {
    let cache: Arc<Cache<String, Value>> = Arc::new(
        Cache::builder()
            .time_to_live(Duration::from_secs(60))
            .build(),
    );
    let immortal_cache: Arc<Cache<String, Value>> = Arc::new(Cache::builder().build());
    let client = Client::builder()
        .pool_idle_timeout(Duration::from_secs(90))
        .build()
        .expect("Failed to build HTTP client");

    let jdbc_pool_cache = Arc::new(Cache::builder().max_capacity(64).build());
    let app_state = AppState {
        cache,
        immortal_cache,
        client,
        process_start_time_seconds: 0,
        process_started_at: Instant::now(),
        pg_registry: Arc::new(PostgresClientRegistry::empty()),
        jdbc_pool_cache,
        gateway_force_camel_case_to_snake_case: false,
        gateway_auto_cast_uuid_filter_values_to_text: true,
        pipeline_registry: None,
        logging_client_name: None,
        gateway_auth_client_name: None,
        gateway_jdbc_allow_private_hosts: true,
        gateway_jdbc_allowed_hosts: vec![],
        prometheus_metrics_enabled: false,
        metrics_state: Arc::new(athena_rs::api::metrics::MetricsState::new()),
    };

    assert!(app_state.cache.weighted_size() == 0);
    assert!(app_state.immortal_cache.weighted_size() == 0);
}

#[tokio::test]
async fn test_cache_expiration() {
    let cache: Arc<Cache<String, Value>> = Arc::new(
        Cache::builder()
            .time_to_live(Duration::from_millis(100))
            .build(),
    );

    let key = "expiring_key".to_string();
    let value = json!({"expires": true});

    cache.insert(key.clone(), value.clone()).await;

    assert!(cache.get(&key).await.is_some());

    tokio::time::sleep(Duration::from_millis(150)).await;

    assert!(cache.get(&key).await.is_none());
}
