"""Project CRUD endpoints.""" from fastapi import APIRouter, Depends, HTTPException from sqlalchemy import select, func from sqlalchemy.ext.asyncio import AsyncSession from app.database import get_db from app.models.project import Project, ClientAsset, ProjectStatus from app.models.gmal import ModelType from app.schemas.project import ProjectCreate, ProjectUpdate, ProjectOut router = APIRouter() @router.post("", response_model=ProjectOut) async def create_project(data: ProjectCreate, db: AsyncSession = Depends(get_db)): project = Project( name=data.name, client_name=data.client_name, description=data.description, model_type=ModelType(data.model_type), ) db.add(project) await db.commit() await db.refresh(project) return _project_out(project, 0) @router.get("", response_model=list[ProjectOut]) async def list_projects(db: AsyncSession = Depends(get_db)): result = await db.execute(select(Project).order_by(Project.created_at.desc())) projects = result.scalars().all() out = [] for p in projects: count_result = await db.execute( select(func.count(ClientAsset.id)).where(ClientAsset.project_id == p.id) ) count = count_result.scalar() or 0 out.append(_project_out(p, count)) return out @router.get("/{project_id}", response_model=ProjectOut) async def get_project(project_id: int, db: AsyncSession = Depends(get_db)): project = await _get_project(project_id, db) count_result = await db.execute( select(func.count(ClientAsset.id)).where(ClientAsset.project_id == project.id) ) return _project_out(project, count_result.scalar() or 0) @router.put("/{project_id}", response_model=ProjectOut) async def update_project(project_id: int, data: ProjectUpdate, db: AsyncSession = Depends(get_db)): project = await _get_project(project_id, db) if data.name is not None: project.name = data.name if data.client_name is not None: project.client_name = data.client_name if data.description is not None: project.description = data.description if data.model_type is not None: project.model_type = ModelType(data.model_type) await db.commit() await db.refresh(project) count_result = await db.execute( select(func.count(ClientAsset.id)).where(ClientAsset.project_id == project.id) ) return _project_out(project, count_result.scalar() or 0) @router.delete("/{project_id}") async def delete_project(project_id: int, db: AsyncSession = Depends(get_db)): project = await _get_project(project_id, db) await db.delete(project) await db.commit() return {"detail": "Project deleted"} async def _get_project(project_id: int, db: AsyncSession) -> Project: result = await db.execute(select(Project).where(Project.id == project_id)) project = result.scalar_one_or_none() if not project: raise HTTPException(status_code=404, detail="Project not found") return project def _project_out(project: Project, asset_count: int) -> ProjectOut: return ProjectOut( id=project.id, name=project.name, client_name=project.client_name, description=project.description, model_type=project.model_type.value, status=project.status.value, source_filename=project.source_filename, parse_stage=project.parse_stage, has_brief_analysis=bool(project.brief_analysis), ai_input_tokens=project.ai_input_tokens or 0, ai_output_tokens=project.ai_output_tokens or 0, ai_cost_usd=float(project.ai_cost_usd or 0), ai_call_count=project.ai_call_count or 0, created_at=project.created_at, updated_at=project.updated_at, asset_count=asset_count, )