from __future__ import annotations from uuid import UUID from fastapi import APIRouter, Depends, HTTPException, Query, status from sqlalchemy.orm import Session from app.db.session import get_db from app.schemas.project import ProjectCreate, ProjectRead, ProjectUpdate from app.services.project_service import ProjectService from app.utils.response import envelope router = APIRouter(prefix="/projects", tags=["projects"]) @router.get("", response_model=dict) def list_projects( limit: int = Query(default=50, ge=1, le=200), offset: int = Query(default=0, ge=0), name: str | None = Query(default=None, min_length=1, max_length=255), db: Session = Depends(get_db), ): projects, total = ProjectService.list_projects(db, limit=limit, offset=offset, name=name) return envelope({"items": [ProjectRead.model_validate(item).model_dump() for item in projects], "total": total, "limit": limit, "offset": offset}) @router.post("", status_code=status.HTTP_201_CREATED, response_model=dict) def create_project(payload: ProjectCreate, db: Session = Depends(get_db)): project = ProjectService.create_project(db, payload) return envelope(ProjectRead.model_validate(project).model_dump()) @router.get("/{project_id}", response_model=dict) def get_project(project_id: UUID, db: Session = Depends(get_db)): project = ProjectService.get_project(db, project_id) if not project: raise HTTPException(status_code=404, detail="Project not found") return envelope(ProjectRead.model_validate(project).model_dump()) @router.patch("/{project_id}", response_model=dict) def update_project(project_id: UUID, payload: ProjectUpdate, db: Session = Depends(get_db)): project = ProjectService.update_project(db, project_id, payload) return envelope(ProjectRead.model_validate(project).model_dump()) @router.delete("/{project_id}", status_code=status.HTTP_200_OK, response_model=dict) def delete_project(project_id: UUID, db: Session = Depends(get_db)): if not ProjectService.delete_project(db, project_id): raise HTTPException(status_code=404, detail="Project not found") return envelope({"deleted": True})