use std::sync::Arc;

use axum::{middleware, Extension};
use tokio::sync::RwLock;
use tower_http::cors::CorsLayer;
use tower_http::trace::TraceLayer;

use crate::agent::ComplianceAgent;
use crate::api::auth_middleware::{require_jwt_auth, JwksState};
use crate::api::routes;
use crate::error::AgentError;

pub async fn start_api_server(agent: ComplianceAgent, port: u16) -> Result<(), AgentError> {
    let mut app = routes::build_router()
        .layer(Extension(Arc::new(agent.clone())))
        .layer(CorsLayer::permissive())
        .layer(TraceLayer::new_for_http());

    if let (Some(kc_url), Some(kc_realm)) =
        (&agent.config.keycloak_url, &agent.config.keycloak_realm)
    {
        let jwks_url = format!("{kc_url}/realms/{kc_realm}/protocol/openid-connect/certs");
        let jwks_state = JwksState {
            jwks: Arc::new(RwLock::new(None)),
            jwks_url,
        };
        tracing::info!("Keycloak JWT auth enabled for realm '{kc_realm}'");
        app = app
            .layer(Extension(jwks_state))
            .layer(middleware::from_fn(require_jwt_auth));
    } else {
        tracing::warn!("Keycloak not configured - API endpoints are unprotected");
    }

    let addr = format!("0.0.0.0:{port}");
    let listener = tokio::net::TcpListener::bind(&addr)
        .await
        .map_err(|e| AgentError::Other(format!("Failed to bind to {addr}: {e}")))?;

    tracing::info!("REST API listening on {addr}");
    axum::serve(listener, app)
        .await
        .map_err(|e| AgentError::Other(format!("API server error: {e}")))?;

    Ok(())
}
