//! HTTP integration tests for gold standard endpoints.
//!
//! Coverage:
//! - Create gold standard
//! - List gold standards
//! - Remove gold standard
//! - Verify agent against gold standard (correct and incorrect answers)

#![allow(clippy::expect_used)]

mod common;

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

use stemedb_api::create_router;

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

    // Create a gold standard
    let create_request = json!({
        "assertion_hash": "a".repeat(64),
        "subject": "Earth",
        "predicate": "has_shape",
        "expected_object": "oblate_spheroid",
        "created_by": "admin_alice"
    });

    let request = Request::builder()
        .uri("/v1/admin/gold-standards")
        .method("POST")
        .header("content-type", "application/json")
        .body(Body::from(serde_json::to_vec(&create_request).expect("JSON")))
        .expect("Request");

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

    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["subject"], "Earth");
    assert_eq!(json["predicate"], "has_shape");
    assert!(json["status"].as_str().expect("status").contains("created"));

    // List gold standards
    let request = Request::builder()
        .uri("/v1/admin/gold-standards")
        .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["count"], 1);

    let gs = &json["gold_standards"][0];
    assert_eq!(gs["subject"], "Earth");
    assert_eq!(gs["predicate"], "has_shape");
    assert_eq!(gs["expected_object"], "oblate_spheroid");
    assert_eq!(gs["created_by"], "admin_alice");
}

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

    // Create a gold standard
    let create_request = json!({
        "assertion_hash": "a".repeat(64),
        "subject": "Semaglutide",
        "predicate": "treats_condition",
        "expected_object": "type_2_diabetes",
        "created_by": "admin"
    });

    let request = Request::builder()
        .uri("/v1/admin/gold-standards")
        .method("POST")
        .header("content-type", "application/json")
        .body(Body::from(serde_json::to_vec(&create_request).expect("JSON")))
        .expect("Request");

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

    // Remove it
    let request = Request::builder()
        .uri("/v1/admin/gold-standards/Semaglutide/treats_condition")
        .method("DELETE")
        .body(Body::empty())
        .expect("Request");

    let response = app.clone().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["removed"], true);

    // List should be empty
    let request = Request::builder()
        .uri("/v1/admin/gold-standards")
        .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["count"], 0);
}

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

    // Create a gold standard
    let create_request = json!({
        "assertion_hash": "a".repeat(64),
        "subject": "Earth",
        "predicate": "has_shape",
        "expected_object": "oblate_spheroid",
        "created_by": "admin"
    });

    let request = Request::builder()
        .uri("/v1/admin/gold-standards")
        .method("POST")
        .header("content-type", "application/json")
        .body(Body::from(serde_json::to_vec(&create_request).expect("JSON")))
        .expect("Request");

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

    // Verify agent with correct answer
    let verify_request = json!({
        "agent_id": "1".repeat(64),
        "subject": "Earth",
        "predicate": "has_shape",
        "agent_object": "oblate_spheroid"
    });

    let request = Request::builder()
        .uri("/v1/admin/verify-agent")
        .method("POST")
        .header("content-type", "application/json")
        .body(Body::from(serde_json::to_vec(&verify_request).expect("JSON")))
        .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["subject"], "Earth");
    assert_eq!(json["predicate"], "has_shape");
    assert_eq!(json["correct"], true);
    assert_eq!(json["agent_answer"], "oblate_spheroid");
    assert_eq!(json["expected_answer"], "oblate_spheroid");
    assert_eq!(json["trust_adjustment"], 0.05); // Reward
    assert_eq!(json["new_trust_score"], 0.55); // 0.5 + 0.05
}

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

    // Create a gold standard
    let create_request = json!({
        "assertion_hash": "a".repeat(64),
        "subject": "Earth",
        "predicate": "has_shape",
        "expected_object": "oblate_spheroid",
        "created_by": "admin"
    });

    let request = Request::builder()
        .uri("/v1/admin/gold-standards")
        .method("POST")
        .header("content-type", "application/json")
        .body(Body::from(serde_json::to_vec(&create_request).expect("JSON")))
        .expect("Request");

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

    // Verify agent with incorrect answer
    let verify_request = json!({
        "agent_id": "2".repeat(64),
        "subject": "Earth",
        "predicate": "has_shape",
        "agent_object": "flat"
    });

    let request = Request::builder()
        .uri("/v1/admin/verify-agent")
        .method("POST")
        .header("content-type", "application/json")
        .body(Body::from(serde_json::to_vec(&verify_request).expect("JSON")))
        .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["subject"], "Earth");
    assert_eq!(json["predicate"], "has_shape");
    assert_eq!(json["correct"], false);
    assert_eq!(json["agent_answer"], "flat");
    assert_eq!(json["expected_answer"], "oblate_spheroid");
    assert_eq!(json["trust_adjustment"], -0.1); // Penalty
    assert_eq!(json["new_trust_score"], 0.4); // 0.5 - 0.1
}

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

    // Verify agent against non-existent gold standard
    let verify_request = json!({
        "agent_id": "3".repeat(64),
        "subject": "NonExistent",
        "predicate": "predicate",
        "agent_object": "answer"
    });

    let request = Request::builder()
        .uri("/v1/admin/verify-agent")
        .method("POST")
        .header("content-type", "application/json")
        .body(Body::from(serde_json::to_vec(&verify_request).expect("JSON")))
        .expect("Request");

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

    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["error"].as_str().expect("error").contains("not found"));
}
