from typing import Any from fastapi import APIRouter, Depends, HTTPException from pydantic import BaseModel, Field from sqlalchemy.orm import Session from app.db.base import get_db from app.shopping.service import ShoppingService router = APIRouter() class ListCreate(BaseModel): name: str = Field(min_length=1, max_length=255) class ListRename(BaseModel): name: str = Field(min_length=1, max_length=255) class ItemInput(BaseModel): text: str = Field(min_length=1, max_length=500) quantity: float | None = None unit: str = "" class ItemsAdd(BaseModel): list_id: int | None = None list_name: str | None = None items: list[ItemInput] = Field(min_length=1) class ItemChecked(BaseModel): checked: bool @router.get("") def get_snapshot(db: Session = Depends(get_db)) -> dict[str, Any]: return ShoppingService(db).snapshot() @router.get("/lists") def list_lists(db: Session = Depends(get_db)) -> list[dict[str, Any]]: return ShoppingService(db).list_lists(include_items=True) @router.post("/lists") def create_list(payload: ListCreate, db: Session = Depends(get_db)) -> dict[str, Any]: try: return ShoppingService(db).create_list(payload.name) except ValueError as exc: raise HTTPException(status_code=400, detail=str(exc)) from exc @router.get("/lists/{list_id}") def get_list(list_id: int, db: Session = Depends(get_db)) -> dict[str, Any]: data = ShoppingService(db).get_list(list_id=list_id) if not data: raise HTTPException(status_code=404, detail="List not found") return data @router.patch("/lists/{list_id}") def rename_list(list_id: int, payload: ListRename, db: Session = Depends(get_db)) -> dict[str, Any]: try: return ShoppingService(db).rename_list(list_id, payload.name) except ValueError as exc: raise HTTPException(status_code=400, detail=str(exc)) from exc @router.delete("/lists/{list_id}") def delete_list(list_id: int, db: Session = Depends(get_db)) -> dict[str, Any]: try: return ShoppingService(db).delete_list(list_id) except ValueError as exc: raise HTTPException(status_code=404, detail=str(exc)) from exc @router.post("/items") def add_items(payload: ItemsAdd, db: Session = Depends(get_db)) -> dict[str, Any]: try: return ShoppingService(db).add_items( [i.model_dump() for i in payload.items], list_id=payload.list_id, list_name=payload.list_name, ) except ValueError as exc: raise HTTPException(status_code=400, detail=str(exc)) from exc @router.patch("/items/{item_id}") def set_item_checked( item_id: int, payload: ItemChecked, db: Session = Depends(get_db), ) -> dict[str, Any]: try: return ShoppingService(db).set_item_checked(item_id, payload.checked) except ValueError as exc: raise HTTPException(status_code=404, detail=str(exc)) from exc @router.delete("/items/{item_id}") def remove_item(item_id: int, db: Session = Depends(get_db)) -> dict[str, Any]: try: return ShoppingService(db).remove_item(item_id) except ValueError as exc: raise HTTPException(status_code=404, detail=str(exc)) from exc @router.post("/lists/{list_id}/clear-checked") def clear_checked(list_id: int, db: Session = Depends(get_db)) -> dict[str, Any]: try: return ShoppingService(db).clear_checked(list_id) except ValueError as exc: raise HTTPException(status_code=404, detail=str(exc)) from exc