from uuid import UUID from fastapi import APIRouter, Depends, Query from sqlalchemy.orm import Session from app.api.schemas import ( BuyingProjectIn, BuyingProjectPatch, DiscoverySearchIn, ProjectCriteriaIn, page, parse_page, ) from app.persistence.db import get_session from app.services.catalog_service import CatalogService from app.services.discovery_service import CandidateRankingService, DiscoverySearchService from app.services.project_service import ProjectService router = APIRouter(prefix="/api/v1") @router.get("/product-categories") def list_product_categories(session: Session = Depends(get_session)): return {"items": CatalogService(session).list_product_categories()} @router.get("/product-categories/{product_category_id}/sources") def list_category_sources(product_category_id: str, session: Session = Depends(get_session)): return {"items": CatalogService(session).sources_for_category(product_category_id)} @router.get("/product-categories/{product_category_id}/available-criteria") def available_criteria_for_category( product_category_id: str, source: str = Query(...), session: Session = Depends(get_session), ): return CatalogService(session).available_criteria(product_category_id, source) @router.get("/buying-templates") def list_buying_templates(session: Session = Depends(get_session)): return {"items": CatalogService(session).list_templates()} @router.post("/buying-projects", status_code=201) def create_buying_project(payload: BuyingProjectIn, session: Session = Depends(get_session)): return ProjectService(session).create(payload.model_dump()) @router.get("/buying-projects") def list_buying_projects(limit: int = 50, offset: int = 0, session: Session = Depends(get_session)): limit, offset = parse_page(limit, offset) items, total = ProjectService(session).list(limit, offset) return page(items, limit, offset, total) @router.get("/buying-projects/{project_id}") def get_buying_project(project_id: UUID, session: Session = Depends(get_session)): return ProjectService(session).get(project_id) @router.patch("/buying-projects/{project_id}") def patch_buying_project(project_id: UUID, payload: BuyingProjectPatch, session: Session = Depends(get_session)): return ProjectService(session).patch(project_id, payload.model_dump(exclude_unset=True)) @router.post("/buying-projects/{project_id}/criteria", status_code=201) def add_buying_project_criteria( project_id: UUID, payload: ProjectCriteriaIn, session: Session = Depends(get_session), ): return ProjectService(session).replace_criteria(project_id, payload.model_dump()) @router.put("/buying-projects/{project_id}/criteria") def put_buying_project_criteria( project_id: UUID, payload: ProjectCriteriaIn, session: Session = Depends(get_session), ): return ProjectService(session).replace_criteria(project_id, payload.model_dump()) @router.get("/buying-projects/{project_id}/criteria") def get_buying_project_criteria(project_id: UUID, session: Session = Depends(get_session)): return ProjectService(session).get_criteria(project_id) @router.get("/buying-projects/{project_id}/available-criteria") def available_criteria(project_id: UUID, session: Session = Depends(get_session)): return ProjectService(session).available_criteria(project_id) @router.get("/buying-projects/{project_id}/discovery-searches") def list_project_searches(project_id: UUID, session: Session = Depends(get_session)): return {"items": DiscoverySearchService(session).list_for_project(project_id)} @router.post("/buying-projects/{project_id}/discovery-searches", status_code=201) def create_project_search(project_id: UUID, payload: DiscoverySearchIn, session: Session = Depends(get_session)): body = payload.model_dump() body["buying_project_id"] = project_id return DiscoverySearchService(session).create(body) @router.get("/buying-projects/{project_id}/candidates") def list_candidates(project_id: UUID, session: Session = Depends(get_session)): return {"items": CandidateRankingService(session).list_candidates(project_id)} @router.get("/buying-projects/{project_id}/candidates/{candidate_id}") def get_candidate(project_id: UUID, candidate_id: UUID, session: Session = Depends(get_session)): return CandidateRankingService(session).get_candidate(project_id, candidate_id) @router.get("/buying-projects/{project_id}/candidates/{candidate_id}/observations") def list_candidate_observations(project_id: UUID, candidate_id: UUID, session: Session = Depends(get_session)): return {"items": CandidateRankingService(session).list_observations(project_id, candidate_id)} @router.get("/buying-projects/{project_id}/shortlist") def list_shortlist(project_id: UUID, session: Session = Depends(get_session)): return {"items": CandidateRankingService(session).list_candidates(project_id, shortlisted_only=True)}