using MealPlan.Api.DTOs.Generators; using MealPlan.Api.Extensions; using MealPlan.Api.Services.Generators; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace MealPlan.Api.Controllers; [ApiController] [Route("api/diet-generator")] [Authorize] public class DietGeneratorController : ControllerBase { private readonly IDietGeneratorService _service; public DietGeneratorController(IDietGeneratorService service) => _service = service; [HttpGet("profile")] [ProducesResponseType(typeof(DietUserProfileDto), StatusCodes.Status200OK)] public async Task GetProfile(CancellationToken ct) { if (User.RequireUserId(out var userId) is { } unauthorized) return unauthorized; var profile = await _service.GetProfileAsync(userId, ct); return Ok(profile ?? new DietUserProfileDto()); } [HttpPut("profile")] [ProducesResponseType(typeof(DietUserProfileDto), StatusCodes.Status200OK)] public async Task UpsertProfile([FromBody] DietUserProfileDto dto, CancellationToken ct) { if (User.RequireUserId(out var userId) is { } unauthorized) return unauthorized; return Ok(await _service.UpsertProfileAsync(userId, dto, ct)); } [HttpPost("sessions")] [ProducesResponseType(typeof(DietGeneratorSessionDto), StatusCodes.Status201Created)] public async Task CreateSession([FromBody] CreateDietGeneratorSessionDto dto, CancellationToken ct) { if (User.RequireUserId(out var userId) is { } unauthorized) return unauthorized; try { var session = await _service.CreateSessionAsync(userId, dto, ct); return CreatedAtAction(nameof(GetSession), new { id = session.Id }, session); } catch (InvalidOperationException ex) { return BadRequest(new { error = ex.Message }); } } [HttpGet("sessions/{id:int}")] [ProducesResponseType(typeof(DietGeneratorSessionDto), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetSession(int id, CancellationToken ct) { if (User.RequireUserId(out var userId) is { } unauthorized) return unauthorized; var session = await _service.GetSessionAsync(userId, id, ct); return session is null ? NotFound() : Ok(session); } [HttpPost("sessions/{id:int}/propose-macros")] [ProducesResponseType(typeof(DietGeneratorSessionDto), StatusCodes.Status200OK)] public async Task ProposeMacros(int id, CancellationToken ct) { if (User.RequireUserId(out var userId) is { } unauthorized) return unauthorized; var session = await _service.ProposeMacrosAsync(userId, id, ct); return session is null ? NotFound() : Ok(session); } [HttpPost("sessions/{id:int}/accept-macros")] [ProducesResponseType(typeof(DietGeneratorSessionDto), StatusCodes.Status200OK)] public async Task AcceptMacros(int id, [FromBody] AcceptMacrosDto dto, CancellationToken ct) { if (User.RequireUserId(out var userId) is { } unauthorized) return unauthorized; var session = await _service.AcceptMacrosAsync(userId, id, dto, ct); return session is null ? NotFound() : Ok(session); } [HttpPost("sessions/{id:int}/generate-plan")] [ProducesResponseType(typeof(DietGeneratorSessionDto), StatusCodes.Status200OK)] public async Task GeneratePlan(int id, CancellationToken ct) { if (User.RequireUserId(out var userId) is { } unauthorized) return unauthorized; try { var session = await _service.GeneratePlanAsync(userId, id, ct); return session is null ? NotFound() : Ok(session); } catch (InvalidOperationException ex) { return BadRequest(new { error = ex.Message }); } } [HttpPost("sessions/{id:int}/regenerate-meal")] [ProducesResponseType(typeof(DietGeneratorSessionDto), StatusCodes.Status200OK)] public async Task RegenerateMeal(int id, [FromBody] RegenerateDietMealDto dto, CancellationToken ct) { if (User.RequireUserId(out var userId) is { } unauthorized) return unauthorized; try { var session = await _service.RegenerateMealAsync(userId, id, dto, ct); return session is null ? NotFound() : Ok(session); } catch (InvalidOperationException ex) { return BadRequest(new { error = ex.Message }); } } [HttpPatch("sessions/{id:int}/meals/{mealId:int}")] [ProducesResponseType(typeof(DietGeneratorSessionDto), StatusCodes.Status200OK)] public async Task UpdateMeal(int id, int mealId, [FromBody] UpdateDraftMealDto dto, CancellationToken ct) { if (User.RequireUserId(out var userId) is { } unauthorized) return unauthorized; var session = await _service.UpdateDraftMealAsync(userId, id, mealId, dto, ct); return session is null ? NotFound() : Ok(session); } [HttpPost("sessions/{id:int}/commit")] [ProducesResponseType(typeof(CommitDietPlanResultDto), StatusCodes.Status200OK)] public async Task Commit(int id, CancellationToken ct) { if (User.RequireUserId(out var userId) is { } unauthorized) return unauthorized; var result = await _service.CommitAsync(userId, id, ct); return result is null ? NotFound() : Ok(result); } }