//! HTTP integration tests for query and filtering operations.
//!
//! Coverage:
//! - GET /v1/query - Subject/predicate filtering
//! - Lens parameter (Recency, Consensus, Confidence, Authority, VoteAwareConsensus)
//! - Lifecycle filtering
//! - Pagination (limit)
//! - Response structure validation

#![allow(clippy::expect_used)]

mod common;

use axum::{
    body::Body,
    http::{Request, StatusCode},
};
use tower::ServiceExt;

use stemedb_api::create_router;

// ============================================================================
// GET /v1/query - Query Assertions Tests
// ============================================================================

#[tokio::test]
async fn test_query_basic_with_subject_predicate() {
    let env = common::create_test_env().await;
    let app = create_router(env.state);

    let request = Request::builder()
        .uri("/v1/query?subject=Test_Entity&predicate=test_property")
        .method("GET")
        .body(Body::empty())
        .expect("Request");

    let response = app.oneshot(request).await.expect("Request");
    assert_eq!(response.status(), StatusCode::OK);

    let body = axum::body::to_bytes(response.into_body(), usize::MAX).await.expect("Body");
    let json: serde_json::Value = serde_json::from_slice(&body).expect("JSON");

    // Verify response structure (empty since DB is empty)
    assert!(json.get("assertions").is_some());
    assert!(json.get("total_count").is_some());
    assert!(json.get("has_more").is_some());
    assert_eq!(json["assertions"], serde_json::json!([]));
    assert_eq!(json["total_count"], 0);
}

#[tokio::test]
async fn test_query_with_lens_recency() {
    let env = common::create_test_env().await;
    let app = create_router(env.state);

    let request = Request::builder()
        .uri("/v1/query?subject=Test&predicate=prop&lens=Recency")
        .method("GET")
        .body(Body::empty())
        .expect("Request");

    let response = app.oneshot(request).await.expect("Request");
    assert_eq!(response.status(), StatusCode::OK);

    let body = axum::body::to_bytes(response.into_body(), usize::MAX).await.expect("Body");
    let json: serde_json::Value = serde_json::from_slice(&body).expect("JSON");

    // When a lens is applied (even with empty results), conflict_score and
    // resolution_confidence should be None (empty result set)
    assert_eq!(json["assertions"], serde_json::json!([]));
    assert_eq!(json["total_count"], 0);
    assert!(json.get("conflict_score").is_none() || json["conflict_score"].is_null());
    assert!(json.get("resolution_confidence").is_none() || json["resolution_confidence"].is_null());
}

#[tokio::test]
async fn test_query_lifecycle_filtering() {
    let env = common::create_test_env().await;
    let app = create_router(env.state);

    let request = Request::builder()
        .uri("/v1/query?subject=Test&lifecycle=Approved")
        .method("GET")
        .body(Body::empty())
        .expect("Request");

    let response = app.oneshot(request).await.expect("Request");
    assert_eq!(response.status(), StatusCode::OK);

    let body = axum::body::to_bytes(response.into_body(), usize::MAX).await.expect("Body");
    let json: serde_json::Value = serde_json::from_slice(&body).expect("JSON");

    assert_eq!(json["assertions"], serde_json::json!([]));
    assert_eq!(json["total_count"], 0);
}

#[tokio::test]
async fn test_query_with_limit() {
    let env = common::create_test_env().await;
    let app = create_router(env.state);

    let request = Request::builder()
        .uri("/v1/query?subject=Test&limit=10")
        .method("GET")
        .body(Body::empty())
        .expect("Request");

    let response = app.oneshot(request).await.expect("Request");
    assert_eq!(response.status(), StatusCode::OK);

    let body = axum::body::to_bytes(response.into_body(), usize::MAX).await.expect("Body");
    let json: serde_json::Value = serde_json::from_slice(&body).expect("JSON");

    // Verify query executes successfully (limit parameter is accepted)
    assert!(json.get("assertions").is_some());
}

#[tokio::test]
async fn test_query_with_all_lenses() {
    let env = common::create_test_env().await;
    let app = create_router(env.state);

    // Test that all lens values are accepted
    let lenses = vec!["Recency", "Consensus", "Confidence", "Authority", "VoteAwareConsensus"];

    for lens in lenses {
        let request = Request::builder()
            .uri(format!("/v1/query?subject=Test&predicate=prop&lens={}", lens))
            .method("GET")
            .body(Body::empty())
            .expect("Request");

        let response = app.clone().oneshot(request).await.expect("Request");
        assert_eq!(response.status(), StatusCode::OK, "Lens {} should be accepted", lens);
    }
}

#[tokio::test]
async fn test_query_response_structure() {
    let env = common::create_test_env().await;
    let app = create_router(env.state);

    let request = Request::builder()
        .uri("/v1/query?subject=Test")
        .method("GET")
        .body(Body::empty())
        .expect("Request");

    let response = app.oneshot(request).await.expect("Request");
    let body = axum::body::to_bytes(response.into_body(), usize::MAX).await.expect("Body");
    let json: serde_json::Value = serde_json::from_slice(&body).expect("JSON");

    // Verify expected fields are present
    assert!(json.get("assertions").is_some());
    assert!(json.get("total_count").is_some());
    assert!(json.get("has_more").is_some());
}

#[tokio::test]
async fn test_query_subject_only() {
    let env = common::create_test_env().await;
    let app = create_router(env.state);

    let request = Request::builder()
        .uri("/v1/query?subject=Entity123")
        .method("GET")
        .body(Body::empty())
        .expect("Request");

    let response = app.oneshot(request).await.expect("Request");
    assert_eq!(response.status(), StatusCode::OK);

    let body = axum::body::to_bytes(response.into_body(), usize::MAX).await.expect("Body");
    let json: serde_json::Value = serde_json::from_slice(&body).expect("JSON");
    assert!(json.get("assertions").is_some());
}

#[tokio::test]
async fn test_query_predicate_only() {
    let env = common::create_test_env().await;
    let app = create_router(env.state);

    let request = Request::builder()
        .uri("/v1/query?predicate=has_property")
        .method("GET")
        .body(Body::empty())
        .expect("Request");

    let response = app.oneshot(request).await.expect("Request");
    assert_eq!(response.status(), StatusCode::OK);

    let body = axum::body::to_bytes(response.into_body(), usize::MAX).await.expect("Body");
    let json: serde_json::Value = serde_json::from_slice(&body).expect("JSON");
    assert!(json.get("assertions").is_some());
}

#[tokio::test]
async fn test_query_empty_params() {
    let env = common::create_test_env().await;
    let app = create_router(env.state);

    let request =
        Request::builder().uri("/v1/query").method("GET").body(Body::empty()).expect("Request");

    let response = app.oneshot(request).await.expect("Request");
    assert_eq!(response.status(), StatusCode::OK);

    let body = axum::body::to_bytes(response.into_body(), usize::MAX).await.expect("Body");
    let json: serde_json::Value = serde_json::from_slice(&body).expect("JSON");
    assert!(json.get("assertions").is_some());
}
