use crate::common::TestServer;
use serde_json::json;

#[tokio::test]
async fn create_list_and_applicable_scans() {
    let server = TestServer::start().await;

    // Initially empty.
    let resp = server.get("/api/v1/targets").await;
    assert_eq!(resp.status(), 200);
    let body: serde_json::Value = resp.json().await.unwrap();
    assert_eq!(body["data"].as_array().unwrap().len(), 0);

    // Create a web-app target with a git repo + a live URL.
    let resp = server
        .post(
            "/api/v1/targets",
            &json!({
                "name": "acme-web",
                "target_type": "web_app",
                "artifacts": [
                    { "kind": "git_repo", "source_ref": "https://git/acme.git", "branch": "main" },
                    { "kind": "live_url", "source_ref": "https://acme.example.com" }
                ]
            }),
        )
        .await;
    assert_eq!(resp.status(), 200);
    let body: serde_json::Value = resp.json().await.unwrap();
    let id = body["data"]["_id"]["$oid"].as_str().unwrap().to_string();
    assert!(!id.is_empty());
    assert_eq!(body["data"]["artifacts"].as_array().unwrap().len(), 2);

    // List returns it.
    let resp = server.get("/api/v1/targets").await;
    let body: serde_json::Value = resp.json().await.unwrap();
    assert_eq!(body["data"].as_array().unwrap().len(), 1);

    // Applicable scans: SAST present + DAST offered (live URL present), pentest supported.
    let resp = server
        .get(&format!("/api/v1/targets/{id}/applicable-scans"))
        .await;
    assert_eq!(resp.status(), 200);
    let body: serde_json::Value = resp.json().await.unwrap();
    let scans = body["data"]["scans"].as_array().unwrap();
    let names: Vec<&str> = scans.iter().filter_map(|s| s["scan"].as_str()).collect();
    assert!(names.contains(&"sast"));
    assert!(names.contains(&"dast"));
    assert_eq!(body["data"]["pentest_supported"], true);

    server.cleanup().await;
}

#[tokio::test]
async fn detect_classifies_a_plc_target() {
    let server = TestServer::start().await;

    // A PLC project artifact is a strong kind-based signal.
    let resp = server
        .post(
            "/api/v1/targets",
            &json!({
                "name": "line-controller",
                "target_type": "backend_service", // deliberately wrong; detect should suggest PLC
                "artifacts": [
                    { "kind": "plc_project", "source_ref": "line.xml", "plc_format": "plcopen_xml" }
                ]
            }),
        )
        .await;
    let body: serde_json::Value = resp.json().await.unwrap();
    let id = body["data"]["_id"]["$oid"].as_str().unwrap().to_string();

    let resp = server
        .post(&format!("/api/v1/targets/{id}/detect"), &json!({}))
        .await;
    assert_eq!(resp.status(), 200);
    let body: serde_json::Value = resp.json().await.unwrap();
    assert_eq!(body["data"]["classification"]["suggested"], "plc_sps");

    server.cleanup().await;
}

#[tokio::test]
async fn add_artifact_and_delete_target() {
    let server = TestServer::start().await;

    let resp = server
        .post(
            "/api/v1/targets",
            &json!({ "name": "svc", "target_type": "backend_service" }),
        )
        .await;
    let body: serde_json::Value = resp.json().await.unwrap();
    let id = body["data"]["_id"]["$oid"].as_str().unwrap().to_string();

    // Attach a git repo.
    let resp = server
        .post(
            &format!("/api/v1/targets/{id}/artifacts"),
            &json!({ "kind": "git_repo", "source_ref": "https://git/svc.git" }),
        )
        .await;
    assert_eq!(resp.status(), 200);
    let body: serde_json::Value = resp.json().await.unwrap();
    assert_eq!(body["data"]["artifacts"].as_array().unwrap().len(), 1);

    // Delete it.
    let resp = server.delete(&format!("/api/v1/targets/{id}")).await;
    assert_eq!(resp.status(), 200);
    let resp = server.get(&format!("/api/v1/targets/{id}")).await;
    assert_eq!(resp.status(), 404);

    server.cleanup().await;
}
