using Health.Application.Diets; namespace Health.WebApi.Endpoints; public static class DietEndpoints { public static void MapDietEndpoints(this WebApplication app) { var group = app.MapGroup("/api/diet-records").RequireAuthorization(); group.MapGet("/", async (string? date, string? mealType, HttpContext http, IDietService diets, CancellationToken ct) => { var userId = GetUserId(http); var records = await diets.ListAsync(userId, date, mealType, ct); return Results.Ok(new { code = 0, data = records, message = (string?)null }); }); group.MapPost("/", async (HttpRequest request, HttpContext http, IDietService diets, CancellationToken ct) => { var userId = GetUserId(http); using var json = JsonDocument.Parse(await ReadBodyAsync(request, ct)); var recordId = await diets.CreateAsync(userId, ReadCreateRequest(json.RootElement), ct); return Results.Ok(new { code = 0, data = new { id = recordId }, message = (string?)null }); }); group.MapDelete("/{id:guid}", async (Guid id, HttpContext http, IDietService diets, CancellationToken ct) => { var userId = GetUserId(http); var deleted = await diets.DeleteAsync(userId, id, ct); return deleted ? Results.Ok(new { code = 0, data = new { success = true }, message = (string?)null }) : Results.Ok(new { code = 40004, data = (object?)null, message = "饮食记录不存在" }); }); group.MapPut("/{id:guid}", async (Guid id, HttpContext http, IDietService diets, CancellationToken ct) => { var userId = GetUserId(http); using var json = JsonDocument.Parse(await ReadBodyAsync(http.Request, ct)); var updated = await diets.UpdateAsync(userId, id, ReadPatchRequest(json.RootElement), ct); if (!updated) return Results.Ok(new { code = 40004, message = "记录不存在" }); return Results.Ok(new { code = 0, data = new { success = true }, message = (string?)null }); }); } private static DietRecordCreateRequest ReadCreateRequest(JsonElement root) { var mealType = Enum.TryParse( root.TryGetProperty("mealType", out var mt) ? mt.GetString() : "Lunch", out var meal) ? meal : MealType.Lunch; var recordedAt = root.TryGetProperty("recordedAt", out var ra) && DateOnly.TryParse(ra.GetString(), out var d) ? d : DateOnly.FromDateTime(DateTime.UtcNow.AddHours(8)); return new DietRecordCreateRequest( mealType, root.TryGetProperty("totalCalories", out var tc) ? tc.GetInt32() : null, root.TryGetProperty("healthScore", out var hs) ? hs.GetInt32() : null, recordedAt, ReadFoodItems(root)); } private static DietRecordPatchRequest ReadPatchRequest(JsonElement root) => new( root.TryGetProperty("totalCalories", out var cal) ? cal.GetInt32() : null, root.TryGetProperty("healthScore", out var hs) ? hs.GetInt32() : null); private static List ReadFoodItems(JsonElement root) { var result = new List(); if (!root.TryGetProperty("foodItems", out var items) || items.ValueKind != JsonValueKind.Array) return result; var i = 0; foreach (var fi in items.EnumerateArray()) { result.Add(new DietFoodItemInput( fi.TryGetProperty("name", out var n) ? n.GetString() ?? "" : "", fi.TryGetProperty("portion", out var p) ? p.GetString() : null, fi.TryGetProperty("calories", out var c) ? c.GetInt32() : null, fi.TryGetProperty("sortOrder", out var so) ? so.GetInt32() : i)); i++; } return result; } private static async Task ReadBodyAsync(HttpRequest request, CancellationToken ct) { request.EnableBuffering(); using var reader = new StreamReader(request.Body, leaveOpen: true); var body = await reader.ReadToEndAsync(ct); request.Body.Position = 0; return string.IsNullOrWhiteSpace(body) ? "{}" : body; } private static Guid GetUserId(HttpContext http) => Guid.TryParse(http.User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value, out var id) ? id : Guid.Empty; }