from typing import List, Optional from fastapi import APIRouter, Depends, HTTPException, status, Query from sqlalchemy.orm import Session from pydantic import BaseModel from app.crud import todo from app.db.session import get_db from app.schemas.todo import TodoCreate, TodoResponse, TodoUpdate router = APIRouter() class BulkCompleteRequest(BaseModel): todo_ids: List[int] @router.get("/", response_model=List[TodoResponse]) def read_todos( skip: int = 0, limit: int = 100, category: Optional[str] = Query(None, description="Filter by category"), completed: Optional[bool] = Query(None, description="Filter by completion status"), overdue_only: bool = Query(False, description="Show only overdue todos"), db: Session = Depends(get_db), ): """ Retrieve todos with pagination and filtering. """ todos = todo.get_multi( db, skip=skip, limit=limit, category=category, completed=completed, overdue_only=overdue_only, ) return todos @router.get("/categories/{category}", response_model=List[TodoResponse]) def read_todos_by_category( *, db: Session = Depends(get_db), category: str, ): """ Get all todos by category. """ return todo.get_by_category(db=db, category=category) @router.get("/overdue", response_model=List[TodoResponse]) def read_overdue_todos( db: Session = Depends(get_db), ): """ Get all overdue todos. """ return todo.get_overdue(db=db) @router.post("/", response_model=TodoResponse, status_code=status.HTTP_201_CREATED) def create_todo( *, db: Session = Depends(get_db), todo_in: TodoCreate, ): """ Create new todo. """ return todo.create(db=db, obj_in=todo_in) @router.get("/{todo_id}", response_model=TodoResponse) def read_todo( *, db: Session = Depends(get_db), todo_id: int, ): """ Get todo by ID. """ todo_obj = todo.get(db=db, todo_id=todo_id) if not todo_obj: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Todo not found" ) return todo_obj @router.put("/{todo_id}", response_model=TodoResponse) def update_todo( *, db: Session = Depends(get_db), todo_id: int, todo_in: TodoUpdate, ): """ Update a todo. """ todo_obj = todo.get(db=db, todo_id=todo_id) if not todo_obj: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Todo not found" ) return todo.update(db=db, db_obj=todo_obj, obj_in=todo_in) @router.delete("/{todo_id}", response_model=TodoResponse) def delete_todo( *, db: Session = Depends(get_db), todo_id: int, ): """ Delete a todo. """ todo_obj = todo.remove(db=db, todo_id=todo_id) if not todo_obj: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Todo not found" ) return todo_obj @router.post("/bulk-complete", response_model=List[TodoResponse]) def bulk_complete_todos( *, db: Session = Depends(get_db), request: BulkCompleteRequest, ): """ Mark multiple todos as completed. """ completed_todos = [] not_found_ids = [] for todo_id in request.todo_ids: todo_obj = todo.get(db=db, todo_id=todo_id) if todo_obj: updated_todo = todo.update( db=db, db_obj=todo_obj, obj_in={"completed": True} ) completed_todos.append(updated_todo) else: not_found_ids.append(todo_id) if not_found_ids: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Todos not found: {not_found_ids}" ) return completed_todos