from __future__ import annotations from uuid import UUID from fastapi import APIRouter, Depends, HTTPException, status from src.application.plans import ( approve_plan, edit_plan, generate_plan, get_plan, list_plans, request_plan_revision, ) from src.application.research import list_research_runs, start_research_run from src.domain.auth import EDITOR_OR_ADMIN_ROLES from src.domain.contracts import ( CurrentUser, PlanListResponse, PlanResponse, PlanRevisionRequest, PlanUpdateRequest, ResearchListResponse, ResearchStartResponse, ReviewActionResponse, ) from src.infrastructure.object_storage import open_object_storage_client from src.infrastructure.repositories import BackendRepository from src.presentation.dependencies import get_repository, require_roles router = APIRouter(prefix="/api", tags=["plans"]) @router.post( "/articles/{article_id}/plan/generate", response_model=PlanResponse, status_code=status.HTTP_201_CREATED, ) def post_generate_plan( article_id: UUID, current_user: CurrentUser = Depends(require_roles(EDITOR_OR_ADMIN_ROLES)), repository: BackendRepository = Depends(get_repository), ) -> PlanResponse: try: return generate_plan(repository, article_id=article_id, current_user=current_user) except LookupError as error: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Not Found") from error except PermissionError as error: raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=str(error)) from error @router.get("/articles/{article_id}/plans", response_model=PlanListResponse) def get_plans( article_id: UUID, _: CurrentUser = Depends(require_roles(EDITOR_OR_ADMIN_ROLES)), repository: BackendRepository = Depends(get_repository), ) -> PlanListResponse: try: return list_plans(repository, article_id=article_id) except LookupError as error: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Not Found") from error @router.get("/articles/{article_id}/plans/{plan_id}", response_model=PlanResponse) def get_plan_route( article_id: UUID, plan_id: UUID, _: CurrentUser = Depends(require_roles(EDITOR_OR_ADMIN_ROLES)), repository: BackendRepository = Depends(get_repository), ) -> PlanResponse: try: return get_plan(repository, article_id=article_id, plan_id=plan_id) except LookupError as error: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Not Found") from error @router.patch( "/articles/{article_id}/plans/{plan_id}", response_model=PlanResponse, status_code=status.HTTP_201_CREATED, ) def patch_plan( article_id: UUID, plan_id: UUID, request: PlanUpdateRequest, current_user: CurrentUser = Depends(require_roles(EDITOR_OR_ADMIN_ROLES)), repository: BackendRepository = Depends(get_repository), ) -> PlanResponse: try: return edit_plan( repository, article_id=article_id, plan_id=plan_id, request=request, current_user=current_user, ) except LookupError as error: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Not Found") from error @router.post( "/articles/{article_id}/plans/{plan_id}/approve", response_model=ReviewActionResponse, ) def post_approve_plan( article_id: UUID, plan_id: UUID, current_user: CurrentUser = Depends(require_roles(EDITOR_OR_ADMIN_ROLES)), repository: BackendRepository = Depends(get_repository), ) -> ReviewActionResponse: try: return approve_plan( repository, article_id=article_id, plan_id=plan_id, current_user=current_user, ) except LookupError as error: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Not Found") from error @router.post( "/articles/{article_id}/plans/{plan_id}/request-revision", response_model=ReviewActionResponse, ) def post_request_plan_revision( article_id: UUID, plan_id: UUID, request: PlanRevisionRequest, current_user: CurrentUser = Depends(require_roles(EDITOR_OR_ADMIN_ROLES)), repository: BackendRepository = Depends(get_repository), ) -> ReviewActionResponse: try: return request_plan_revision( repository, article_id=article_id, plan_id=plan_id, request=request, current_user=current_user, ) except LookupError as error: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Not Found") from error @router.post( "/articles/{article_id}/research/start", response_model=ResearchStartResponse, status_code=status.HTTP_201_CREATED, ) def post_start_research( article_id: UUID, _: CurrentUser = Depends(require_roles(EDITOR_OR_ADMIN_ROLES)), repository: BackendRepository = Depends(get_repository), ) -> ResearchStartResponse: try: return start_research_run( repository, article_id=article_id, object_storage=open_object_storage_client(), ) except LookupError as error: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Not Found") from error except PermissionError as error: raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=str(error)) from error @router.get( "/articles/{article_id}/research", response_model=ResearchListResponse, ) def get_research( article_id: UUID, _: CurrentUser = Depends(require_roles(EDITOR_OR_ADMIN_ROLES)), repository: BackendRepository = Depends(get_repository), ) -> ResearchListResponse: try: return list_research_runs(repository, article_id=article_id) except LookupError as error: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Not Found") from error