from __future__ import annotations from typing import List, Set from meals.models import Meal from api.dtos import MemberRef def get_duplicates(items: List[MemberRef]) -> Set[str]: """Return the set of duplicate person names based on repeated ids.""" seen: set[int] = set() duplicates: set[str] = set() for item in items: if item.id in seen: # prefer display_name; fall back to best-effort repr name = ( getattr(item, "display_name", None) or getattr(item, "name", None) or str(item.id) ) duplicates.add(name) seen.add(item.id) return duplicates def validate_meal(meal: Meal) -> str | None: """Validate a Meal domain model. Returns: None if valid, otherwise a human-readable error message. """ if not meal.chefs: return "Meal must have at least one chef" if not meal.cleanup: return "Meal must have at least one cleanup person" if not meal.consumers: return "Meal must have at least one consumer" if len(meal.recipes) == 0 and len(meal.extra_ingredients) == 0: return "Meal must have at least one recipe or ingredient" duplicates = get_duplicates(meal.chefs) if duplicates: return f"Duplicate chef: {', '.join(duplicates)}" duplicates = get_duplicates(meal.cleanup) if duplicates: return f"Duplicate cleanup person: {', '.join(duplicates)}" duplicates = get_duplicates(meal.consumers) if duplicates: return f"Duplicate consumer: {', '.join(duplicates)}" zero_servings = [r for r in meal.recipes if r.servings == 0] if zero_servings: return "Recipe servings must be greater than 0" return None