use axum::{
    Json, Router,
    extract::{Path, Query, State},
    http::StatusCode,
    response::IntoResponse,
    routing::{get, post},
};
use serde::Deserialize;

use crate::access::{AccessControl, AgentRole};

pub fn router(ac: AccessControl) -> Router {
    Router::new()
        .route("/roles", get(list_roles))
        .route("/roles", post(set_role))
        // Scrum iter 11 / P13-001 finding: get_role was #[allow(dead_code)]
        // because nothing called it — dead until exposed. Route activates it.
        // Returns 404 when the agent isn't registered so clients can
        // distinguish "missing role" from "access denied."
        .route("/roles/{agent}", get(get_role))
        .route("/enabled", get(enabled_status))
        .route("/audit", get(query_audit))
        .route("/check", post(check_access))
        .with_state(ac)
}

async fn list_roles(State(ac): State<AccessControl>) -> impl IntoResponse {
    Json(ac.list_roles().await)
}

async fn set_role(
    State(ac): State<AccessControl>,
    Json(role): Json<AgentRole>,
) -> impl IntoResponse {
    let name = role.agent_name.clone();
    ac.set_role(role).await;
    (StatusCode::OK, format!("role set: {name}"))
}

#[derive(Deserialize)]
struct AuditQuery {
    limit: Option<usize>,
}

async fn query_audit(
    State(ac): State<AccessControl>,
    Query(q): Query<AuditQuery>,
) -> impl IntoResponse {
    Json(ac.recent_audit(q.limit.unwrap_or(50)).await)
}

#[derive(Deserialize)]
struct CheckRequest {
    agent: String,
    sensitivity: shared::types::Sensitivity,
}

async fn check_access(
    State(ac): State<AccessControl>,
    Json(req): Json<CheckRequest>,
) -> impl IntoResponse {
    let allowed = ac.can_access(&req.agent, &req.sensitivity).await;
    Json(serde_json::json!({
        "agent": req.agent,
        "sensitivity": req.sensitivity,
        "allowed": allowed,
    }))
}

async fn get_role(
    State(ac): State<AccessControl>,
    Path(agent): Path<String>,
) -> impl IntoResponse {
    match ac.get_role(&agent).await {
        Some(role) => Ok(Json(role)),
        None => Err((StatusCode::NOT_FOUND, format!("no role registered for agent '{agent}'"))),
    }
}

async fn enabled_status(State(ac): State<AccessControl>) -> impl IntoResponse {
    Json(serde_json::json!({ "enabled": ac.is_enabled() }))
}
