use axum::body::Body;
use axum::http::{Request, StatusCode};
use extension_registry::config::OciConfig;
use extension_registry::{build_routes, AppState, Config};
use http_body_util::BodyExt;
use tower::ServiceExt;

/// Create a minimal test config with a mock OCI backend
fn create_test_config() -> Config {
    Config {
        server: extension_registry::config::ServerConfig::default(),
        gitea: None,
        // Use OCI as test backend (doesn't require file validation for auth_token_path)
        oci: Some(OciConfig {
            id: Some("test-oci".to_string()),
            registry: "localhost:5000".to_string(),
            namespace: "test".to_string(),
            auth_token_path: None,
            timeout_seconds: 30,
            verify_ssl: false,
        }),
        sources: extension_registry::config::SourcesConfig::default(),
        distributions: extension_registry::config::DistributionsConfig::default(),
        cache: extension_registry::config::CacheConfig::default(),
    }
}

#[tokio::test]
#[ignore] // Requires OCI registry or Gitea service to be running
#[ignore] // Requires OCI registry service to be running
async fn test_health_check() {
    let config = create_test_config();
    let state = AppState::new(config, None)
        .await
        .expect("Failed to create app state");
    let app = build_routes(state);

    let response = app
        .oneshot(
            Request::builder()
                .uri("/api/v1/health")
                .body(Body::empty())
                .unwrap(),
        )
        .await
        .unwrap();

    assert_eq!(response.status(), StatusCode::OK);

    let body = response.into_body().collect().await.unwrap().to_bytes();
    let health: serde_json::Value = serde_json::from_slice(&body).unwrap();

    assert!(health.get("status").is_some());
    assert!(health.get("version").is_some());
    assert!(health.get("uptime").is_some());
}

#[tokio::test]
#[ignore] // Requires OCI registry or Gitea service to be running
async fn test_list_extensions_empty() {
    let config = create_test_config();
    let state = AppState::new(config, None)
        .await
        .expect("Failed to create app state");
    let app = build_routes(state);

    let response = app
        .oneshot(
            Request::builder()
                .uri("/api/v1/extensions")
                .body(Body::empty())
                .unwrap(),
        )
        .await
        .unwrap();

    assert_eq!(response.status(), StatusCode::OK);

    let body = response.into_body().collect().await.unwrap().to_bytes();
    let extensions: Vec<serde_json::Value> = serde_json::from_slice(&body).unwrap();

    // Should be empty when no backends configured
    assert_eq!(extensions.len(), 0);
}

#[tokio::test]
#[ignore] // Requires OCI registry or Gitea service to be running
async fn test_get_nonexistent_extension() {
    let config = create_test_config();

    let state = AppState::new(config, None)
        .await
        .expect("Failed to create app state");
    let app = build_routes(state);

    let response = app
        .oneshot(
            Request::builder()
                .uri("/api/v1/extensions/provider/nonexistent")
                .body(Body::empty())
                .unwrap(),
        )
        .await
        .unwrap();

    assert_eq!(response.status(), StatusCode::NOT_FOUND);
}

#[tokio::test]
#[ignore] // Requires OCI registry or Gitea service to be running
async fn test_metrics_endpoint() {
    let config = create_test_config();

    let state = AppState::new(config, None)
        .await
        .expect("Failed to create app state");
    let app = build_routes(state);

    let response = app
        .oneshot(
            Request::builder()
                .uri("/api/v1/metrics")
                .body(Body::empty())
                .unwrap(),
        )
        .await
        .unwrap();

    assert_eq!(response.status(), StatusCode::OK);

    let body = response.into_body().collect().await.unwrap().to_bytes();
    let metrics = String::from_utf8(body.to_vec()).unwrap();

    assert!(metrics.contains("http_requests_total"));
}

#[tokio::test]
#[ignore] // Requires OCI registry or Gitea service to be running
async fn test_cache_stats_endpoint() {
    let config = create_test_config();

    let state = AppState::new(config, None)
        .await
        .expect("Failed to create app state");
    let app = build_routes(state);

    let response = app
        .oneshot(
            Request::builder()
                .uri("/api/v1/cache/stats")
                .body(Body::empty())
                .unwrap(),
        )
        .await
        .unwrap();

    assert_eq!(response.status(), StatusCode::OK);

    let body = response.into_body().collect().await.unwrap().to_bytes();
    let stats: serde_json::Value = serde_json::from_slice(&body).unwrap();

    assert!(stats.get("list_entries").is_some());
    assert!(stats.get("metadata_entries").is_some());
    assert!(stats.get("total_entries").is_some());
}

#[tokio::test]
#[ignore] // Requires OCI registry or Gitea service to be running
async fn test_invalid_extension_type() {
    let config = create_test_config();

    let state = AppState::new(config, None)
        .await
        .expect("Failed to create app state");
    let app = build_routes(state);

    let response = app
        .oneshot(
            Request::builder()
                .uri("/api/v1/extensions/invalid_type/test")
                .body(Body::empty())
                .unwrap(),
        )
        .await
        .unwrap();

    assert_eq!(response.status(), StatusCode::BAD_REQUEST);
}
