//! OSCAL assessment endpoint.
//!
//! Returns a standard OSCAL assessment-results document for a target's findings,
//! driven by each finding's stamped `control_refs` (from the scan's control-triage
//! stage): mapped findings target their controls, unmapped findings are reported
//! as-is. See `compliance_core::models::oscal_assessment`.

use axum::extract::Extension;
use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use axum::Json;
use mongodb::bson::doc;
use serde::Deserialize;

use compliance_core::models::oscal_assessment::assess;
use compliance_core::models::Finding;
use compliance_core::tenant_ctx::TenantCtx;

use super::dto::{collect_cursor_async, tenant_db, AgentExt};

#[derive(Debug, Deserialize)]
pub struct AssessRequest {
    /// The target / repo id whose findings are assessed.
    pub target_id: String,
}

/// `POST /api/v1/oscal/assess` — OSCAL assessment-results for a target's findings.
pub async fn assess_target(
    Extension(agent): AgentExt,
    tenant: TenantCtx,
    Json(req): Json<AssessRequest>,
) -> Response {
    let db = match tenant_db(&agent, &tenant).await {
        Ok(db) => db,
        Err(code) => return code.into_response(),
    };

    let findings: Vec<Finding> = match db.findings().find(doc! { "repo_id": &req.target_id }).await
    {
        Ok(cursor) => collect_cursor_async(cursor).await,
        Err(e) => {
            tracing::warn!(error = %e, "failed to load findings for OSCAL assessment");
            return StatusCode::INTERNAL_SERVER_ERROR.into_response();
        }
    };

    Json(assess(&findings, chrono::Utc::now())).into_response()
}
