use crate::ui::state::AppState;
use axum::Json;
use axum::extract::{Path, Query, State};
use axum::http::StatusCode;
use axum::response::IntoResponse;
use serde::Deserialize;
use serde_json::json;
use std::sync::Arc;
#[derive(Deserialize)]
pub struct ListQuery {
#[serde(default)]
pub category: Option<String>,
#[serde(default)]
pub limit: Option<usize>,
}
pub async fn list_examples(
State(state): State<Arc<AppState>>,
Query(q): Query<ListQuery>,
) -> impl IntoResponse {
let limit = q.limit.unwrap_or(20);
let entries: Vec<_> = state
.knowledge_base
.all()
.iter()
.filter(|e| q.category.as_deref().is_none_or(|c| e.category == c))
.take(limit)
.map(|e| {
json!({
"id": e.id,
"title": e.title,
"description": e.description,
"category": e.category,
"tags": e.tags,
"complexity": format!("{:?}", e.complexity).to_lowercase(),
})
})
.collect();
(StatusCode::OK, Json(json!({ "examples": entries })))
}
pub async fn get_example(
State(state): State<Arc<AppState>>,
Path(id): Path<String>,
) -> impl IntoResponse {
match state.knowledge_base.by_id(&id) {
Some(entry) => (StatusCode::OK, Json(json!(entry))).into_response(),
None => (
StatusCode::NOT_FOUND,
Json(json!({"error": format!("knowledge entry not found: {id}")})),
)
.into_response(),
}
}
#[derive(Deserialize)]
pub struct SuggestQuery {
pub q: String,
#[serde(default)]
pub limit: Option<usize>,
}
pub async fn suggest(
State(state): State<Arc<AppState>>,
Query(q): Query<SuggestQuery>,
) -> impl IntoResponse {
let limit = q.limit.unwrap_or(5);
let results = state.knowledge_base.suggest(&q.q, limit);
(StatusCode::OK, Json(json!({ "results": results })))
}