use axum::{ extract::{Query, State}, Json, }; use serde::Deserialize; use serde_json::{json, Value}; use crate::{ app::AppState, error::AppResult, models::match_result::{Match, MatchRewardResult, SubmitMatchRequest}, services::{club as club_svc, match_service, profile as profile_svc}, }; #[derive(Deserialize)] pub struct MatchHistoryQuery { pub limit: Option, pub mode: Option, } pub async fn get_matches( State(state): State, Query(query): Query, ) -> AppResult> { let profile = profile_svc::get_active_profile(&state.pool).await?; let limit = query.limit.unwrap_or(20).clamp(1, 100); let matches = if let Some(mode) = &query.mode { sqlx::query_as::<_, Match>( "SELECT id, profile_id, squad_id, opponent_name, goals_for, goals_against, outcome, coins_awarded, xp_awarded, mode, played_at FROM matches WHERE profile_id = ? AND mode = ? ORDER BY played_at DESC LIMIT ?" ) .bind(&profile.id) .bind(mode) .bind(limit) .fetch_all(&state.pool) .await? } else { sqlx::query_as::<_, Match>( "SELECT id, profile_id, squad_id, opponent_name, goals_for, goals_against, outcome, coins_awarded, xp_awarded, mode, played_at FROM matches WHERE profile_id = ? ORDER BY played_at DESC LIMIT ?" ) .bind(&profile.id) .bind(limit) .fetch_all(&state.pool) .await? }; Ok(Json(json!({ "matches": matches, "total": matches.len() }))) } #[derive(Deserialize)] pub struct OpponentQuery { pub difficulty: Option, } pub async fn get_opponent( State(state): State, Query(query): Query, ) -> AppResult> { let difficulty = query.difficulty.as_deref().unwrap_or("beginner"); let opponent = match_service::generate_opponent(&state.card_db, difficulty); Ok(Json(opponent)) } pub async fn post_match_result( State(state): State, Json(req): Json, ) -> AppResult> { let profile = profile_svc::get_active_profile(&state.pool).await?; let club = club_svc::get_club_by_profile(&state.pool, &profile.id).await?; let result = match_service::process_match( &state.pool, &profile.id, &club.id, &req, &state.obj_defs, &state.achievement_defs, ) .await?; Ok(Json(result)) }