package com.recipeapp.planning; import com.recipeapp.common.RequiresHouseholdRole; import com.recipeapp.planning.dto.*; import com.recipeapp.recipe.HouseholdResolver; import jakarta.validation.Valid; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.security.Principal; import java.time.LocalDate; import java.util.List; import java.util.UUID; @RestController @RequestMapping("/v1/week-plans") public class WeekPlanController { private final PlanningService planningService; private final HouseholdResolver householdResolver; public WeekPlanController(PlanningService planningService, HouseholdResolver householdResolver) { this.planningService = planningService; this.householdResolver = householdResolver; } @GetMapping public WeekPlanResponse getWeekPlan(Principal principal, @RequestParam LocalDate weekStart) { UUID householdId = householdResolver.resolve(principal.getName()); return planningService.getWeekPlan(householdId, weekStart); } @PostMapping public ResponseEntity createWeekPlan( Principal principal, @Valid @RequestBody CreateWeekPlanRequest request) { UUID householdId = householdResolver.resolve(principal.getName()); WeekPlanResponse response = planningService.createWeekPlan(householdId, request.weekStart()); return ResponseEntity.status(HttpStatus.CREATED).body(response); } @PostMapping("/{id}/slots") @RequiresHouseholdRole("planner") public ResponseEntity addSlot( Principal principal, @PathVariable UUID id, @Valid @RequestBody CreateSlotRequest request) { UUID householdId = householdResolver.resolve(principal.getName()); SlotResponse response = planningService.addSlot(householdId, id, request); return ResponseEntity.status(HttpStatus.CREATED).body(response); } @PatchMapping("/{planId}/slots/{slotId}") @RequiresHouseholdRole("planner") public SlotResponse updateSlot( Principal principal, @PathVariable UUID planId, @PathVariable UUID slotId, @Valid @RequestBody UpdateSlotRequest request) { UUID householdId = householdResolver.resolve(principal.getName()); return planningService.updateSlot(householdId, planId, slotId, request); } @DeleteMapping("/{planId}/slots/{slotId}") @ResponseStatus(HttpStatus.NO_CONTENT) @RequiresHouseholdRole("planner") public void deleteSlot( Principal principal, @PathVariable UUID planId, @PathVariable UUID slotId) { UUID householdId = householdResolver.resolve(principal.getName()); planningService.deleteSlot(householdId, planId, slotId); } @PostMapping("/{id}/confirm") public WeekPlanResponse confirmPlan(Principal principal, @PathVariable UUID id) { UUID householdId = householdResolver.resolve(principal.getName()); return planningService.confirmPlan(householdId, id); } @GetMapping("/{id}/suggestions") public SuggestionResponse getSuggestions( Principal principal, @PathVariable UUID id, @RequestParam LocalDate slotDate, @RequestParam(required = false) List tags, @RequestParam(required = false) Integer topN) { UUID householdId = householdResolver.resolve(principal.getName()); return planningService.getSuggestions(householdId, id, slotDate, tags != null ? tags : List.of(), topN); } @GetMapping("/{id}/variety-score") public VarietyScoreResponse getVarietyScore(Principal principal, @PathVariable UUID id) { UUID householdId = householdResolver.resolve(principal.getName()); return planningService.getVarietyScore(householdId, id); } @GetMapping("/{planId}/variety-preview") @RequiresHouseholdRole("member") public VarietyPreviewResponse getVarietyPreview( Principal principal, @PathVariable UUID planId, @RequestParam UUID recipeId, @RequestParam LocalDate date) { UUID householdId = householdResolver.resolve(principal.getName()); return planningService.getVarietyPreview(householdId, planId, recipeId, date); } }