using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using MealPlanner.Services; namespace MealPlanner.Controllers; [ApiController] [Route("api/mealplan")] [Authorize] public class MealPlanController(MealPlanService mealPlanService) : ControllerBase { private string UserId => User.FindFirst("sub")?.Value ?? throw new UnauthorizedAccessException(); public record GenerateRequest(string? WeekStart); public record SwapRequest(Guid RecipeId); [HttpPost("generate")] public async Task Generate([FromBody] GenerateRequest? body) { DateOnly weekStart; if (body?.WeekStart is not null && DateOnly.TryParse(body.WeekStart, out var parsed)) { weekStart = MealPlanService.GetWeekStart(parsed); } else { weekStart = MealPlanService.GetWeekStart(DateOnly.FromDateTime(DateTime.UtcNow)); } var plan = await mealPlanService.GenerateWeekPlanAsync(UserId, weekStart); return Ok(plan); } [HttpGet("current")] public async Task GetCurrent() { var plan = await mealPlanService.GetCurrentPlanAsync(UserId); if (plan is null) return NotFound(); return Ok(plan); } [HttpGet("{weekStart}")] public async Task GetByWeek(string weekStart) { if (!DateOnly.TryParse(weekStart, out var date)) return BadRequest("Invalid date format."); var plan = await mealPlanService.GetPlanAsync(UserId, date); if (plan is null) return NotFound(); return Ok(plan); } [HttpPut("{id:guid}/entry/{date}")] public async Task SwapEntry(Guid id, string date, [FromBody] SwapRequest body) { if (!DateOnly.TryParse(date, out var parsedDate)) return BadRequest("Invalid date format."); // Find entry by plan id + date var plan = await mealPlanService.GetPlanAsync(UserId, MealPlanService.GetWeekStart(parsedDate)); if (plan is null || plan.Id != id) return NotFound(); var entry = plan.Entries.FirstOrDefault(e => e.Date == parsedDate); if (entry is null) return NotFound(); try { var updated = await mealPlanService.SwapEntryAsync(entry.Id, body.RecipeId, UserId); if (updated is null) return NotFound(); return Ok(updated); } catch (UnauthorizedAccessException) { return Forbid(); } } [HttpPost("{id:guid}/entry/{date}/reroll")] public async Task RerollEntry(Guid id, string date) { if (!DateOnly.TryParse(date, out var parsedDate)) return BadRequest("Invalid date format."); var plan = await mealPlanService.GetPlanAsync(UserId, MealPlanService.GetWeekStart(parsedDate)); if (plan is null || plan.Id != id) return NotFound(); var entry = plan.Entries.FirstOrDefault(e => e.Date == parsedDate); if (entry is null) return NotFound(); try { var updated = await mealPlanService.RerollEntryAsync(entry.Id, UserId); if (updated is null) return StatusCode(503, "Could not fetch a new recipe. Try again."); return Ok(updated); } catch (UnauthorizedAccessException) { return Forbid(); } } }