use axum::{ extract::{Path, Query, State}, http::StatusCode, routing::{delete, get, post}, Json, Router, }; use serde::Deserialize; use uuid::Uuid; use crate::models::{CreateTrack, Track}; use crate::AppState; pub fn routes(state: AppState) -> Router { Router::new() .route("/tracks", get(list_tracks)) .route("/tracks", post(create_track)) .route("/tracks/:id", get(get_track)) .route("/tracks/:id", delete(delete_track)) .route("/tracks/search", get(search_tracks)) .route("/stats", get(get_stats)) .with_state(state) } async fn list_tracks(State(state): State) -> Json> { let agg = state.read().await; Json(agg.get_all().to_vec()) } async fn create_track( State(state): State, Json(input): Json, ) -> (StatusCode, Json) { let mut agg = state.write().await; let track = agg.add_track(input.into()); (StatusCode::CREATED, Json(track)) } async fn get_track( State(state): State, Path(id): Path, ) -> Result, StatusCode> { let agg = state.read().await; agg.get_by_id(id) .cloned() .map(Json) .ok_or(StatusCode::NOT_FOUND) } async fn delete_track( State(state): State, Path(id): Path, ) -> StatusCode { let mut agg = state.write().await; if agg.delete(id) { StatusCode::NO_CONTENT } else { StatusCode::NOT_FOUND } } #[derive(Deserialize)] struct SearchQuery { artist: String, } async fn search_tracks( State(state): State, Query(query): Query, ) -> Json> { let agg = state.read().await; Json(agg.search_by_artist(&query.artist).into_iter().cloned().collect()) } #[derive(serde::Serialize)] struct Stats { track_count: usize, total_duration_secs: u32, } async fn get_stats(State(state): State) -> Json { let agg = state.read().await; Json(Stats { track_count: agg.get_all().len(), total_duration_secs: agg.total_duration(), }) }