from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from app.database import get_db from app.models import FamilyProfile, FamilyMember, DayOfWeek, MealType, MealPlanStatus, MealPlanItemStatus, ApprovalTokenStatus, FamilyMemberRole, DenialReason, NeverSuggestReason, ScrapeStatus, EmailStatus from app.schemas import ( FamilyProfileResponse, FamilyProfileUpdate, FamilyProfileCreate, FamilyMemberResponse, FamilyMemberCreate ) from app.schemas.planner_config import PlannerConfigOverride, PlannerConfigResponse, PlannerConfigUpdateRequest from app.services.planner.config import DEFAULT from app.security import require_session from uuid import UUID from typing import List router = APIRouter() @router.get("", response_model=FamilyProfileResponse) def get_profile(db: Session = Depends(get_db)): profile = db.query(FamilyProfile).first() if not profile: raise HTTPException(status_code=404, detail="Family profile not found") return profile @router.put("", response_model=FamilyProfileResponse, dependencies=[Depends(require_session)]) def update_profile(update: FamilyProfileUpdate, db: Session = Depends(get_db)): profile = db.query(FamilyProfile).first() if not profile: raise HTTPException(status_code=404, detail="Family profile not found") update_data = update.model_dump(exclude_unset=True) for field, value in update_data.items(): setattr(profile, field, value) db.commit() db.refresh(profile) return profile @router.get("/members", response_model=List[FamilyMemberResponse]) def get_members(db: Session = Depends(get_db)): profile = db.query(FamilyProfile).first() if not profile: raise HTTPException(status_code=404, detail="Family profile not found") return profile.members @router.post("/members", response_model=FamilyMemberResponse, dependencies=[Depends(require_session)]) def add_member(member: FamilyMemberCreate, db: Session = Depends(get_db)): profile = db.query(FamilyProfile).first() if not profile: raise HTTPException(status_code=404, detail="Family profile not found") existing = db.query(FamilyMember).filter( FamilyMember.family_profile_id == profile.id, FamilyMember.email == member.email ).first() if existing: raise HTTPException(status_code=400, detail="Member with this email already exists") db_member = FamilyMember( family_profile_id=profile.id, name=member.name, email=member.email, role=FamilyMemberRole[member.role.value.upper()], likes_mushrooms=member.likes_mushrooms ) db.add(db_member) db.commit() db.refresh(db_member) return db_member @router.delete("/members/{member_id}", dependencies=[Depends(require_session)]) def delete_member(member_id: UUID, db: Session = Depends(get_db)): member = db.query(FamilyMember).filter(FamilyMember.id == member_id).first() if not member: raise HTTPException(status_code=404, detail="Family member not found") db.delete(member) db.commit() return {"message": "Member deleted"} @router.get("/planner-config", response_model=PlannerConfigResponse) def get_planner_config(db: Session = Depends(get_db)): """Return the effective planner configuration for the family (merged defaults + overrides).""" profile = db.query(FamilyProfile).first() if not profile: raise HTTPException(status_code=404, detail="Family profile not found") effective = DEFAULT if profile.planner_config: try: effective = DEFAULT.merge(profile.planner_config) except ValueError: pass # fall back to default data = effective.to_dict() data["source"] = "family_override" if profile.planner_config else "default" return data @router.put("/planner-config", response_model=PlannerConfigResponse, dependencies=[Depends(require_session)]) def update_planner_config(payload: PlannerConfigUpdateRequest, db: Session = Depends(get_db)): """Update the family planner_config. Partial overrides are merged into defaults.""" profile = db.query(FamilyProfile).first() if not profile: raise HTTPException(status_code=404, detail="Family profile not found") # Build a clean dict of overrides overrides = payload.planner_config.model_dump(exclude_unset=True, exclude_none=True) if not overrides: raise HTTPException(status_code=400, detail="No overrides provided") # Merge with existing family config if present existing = dict(profile.planner_config) if profile.planner_config else {} merged = {**existing, **overrides} # Validate via PlannerConfig try: DEFAULT.merge(merged) except Exception as exc: raise HTTPException(status_code=400, detail=f"Invalid planner config: {exc}") profile.planner_config = merged db.commit() db.refresh(profile) effective = DEFAULT.merge(merged) data = effective.to_dict() data["source"] = "family_override" return data @router.delete("/planner-config", dependencies=[Depends(require_session)]) def reset_planner_config(db: Session = Depends(get_db)): """Clear family planner_config and restore system defaults.""" profile = db.query(FamilyProfile).first() if not profile: raise HTTPException(status_code=404, detail="Family profile not found") profile.planner_config = None db.commit() data = DEFAULT.to_dict() data["source"] = "default" return data