from fastapi import APIRouter, Depends, HTTPException, status from admin_app.api.dependencies import ( get_settings, get_tool_management_service, require_panel_admin_permission, ) from admin_app.api.schemas import ( AdminToolContractsResponse, AdminToolDraftIntakeRequest, AdminToolDraftIntakeResponse, AdminToolDraftListResponse, AdminToolManagementActionResponse, AdminToolOverviewResponse, AdminToolPublicationListResponse, AdminToolReviewQueueResponse, ) from admin_app.core import AdminSettings, AuthenticatedStaffPrincipal from admin_app.services import ToolManagementService from shared.contracts import AdminPermission router = APIRouter(prefix="/panel/tools", tags=["panel-tools"]) @router.get( "/overview", response_model=AdminToolOverviewResponse, ) def panel_tools_overview( settings: AdminSettings = Depends(get_settings), service: ToolManagementService = Depends(get_tool_management_service), _: AuthenticatedStaffPrincipal = Depends( require_panel_admin_permission(AdminPermission.MANAGE_TOOL_DRAFTS) ), ): payload = service.build_overview_payload() return AdminToolOverviewResponse( service="orquestrador-admin", mode=payload["mode"], metrics=payload["metrics"], workflow=payload["workflow"], actions=_build_panel_actions(settings), next_steps=payload["next_steps"], ) @router.get( "/contracts", response_model=AdminToolContractsResponse, ) def panel_tool_contracts( service: ToolManagementService = Depends(get_tool_management_service), _current_staff: AuthenticatedStaffPrincipal = Depends( require_panel_admin_permission(AdminPermission.MANAGE_TOOL_DRAFTS) ), ): payload = service.build_contracts_payload() return AdminToolContractsResponse( service="orquestrador-admin", publication_source_service=payload["publication_source_service"], publication_target_service=payload["publication_target_service"], lifecycle_statuses=payload["lifecycle_statuses"], parameter_types=payload["parameter_types"], publication_fields=payload["publication_fields"], published_tool_fields=payload["published_tool_fields"], ) @router.get( "/drafts", response_model=AdminToolDraftListResponse, ) def panel_tool_drafts( service: ToolManagementService = Depends(get_tool_management_service), _current_staff: AuthenticatedStaffPrincipal = Depends( require_panel_admin_permission(AdminPermission.MANAGE_TOOL_DRAFTS) ), ): payload = service.build_drafts_payload() return AdminToolDraftListResponse( service="orquestrador-admin", storage_status=payload["storage_status"], message=payload["message"], drafts=payload["drafts"], supported_statuses=payload["supported_statuses"], ) @router.post( "/drafts/intake", response_model=AdminToolDraftIntakeResponse, ) def panel_tool_draft_intake( draft: AdminToolDraftIntakeRequest, service: ToolManagementService = Depends(get_tool_management_service), current_staff: AuthenticatedStaffPrincipal = Depends( require_panel_admin_permission(AdminPermission.MANAGE_TOOL_DRAFTS) ), ): try: payload = service.create_draft_submission( draft.model_dump(), owner_staff_account_id=current_staff.id, owner_name=current_staff.display_name, ) except ValueError as exc: raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_CONTENT, detail=str(exc), ) from exc return AdminToolDraftIntakeResponse( service="orquestrador-admin", storage_status=payload["storage_status"], message=payload["message"], draft_preview=payload["draft_preview"], warnings=payload["warnings"], next_steps=payload["next_steps"], ) @router.get( "/review-queue", response_model=AdminToolReviewQueueResponse, ) def panel_tool_review_queue( service: ToolManagementService = Depends(get_tool_management_service), _current_staff: AuthenticatedStaffPrincipal = Depends( require_panel_admin_permission(AdminPermission.REVIEW_TOOL_GENERATIONS) ), ): payload = service.build_review_queue_payload() return AdminToolReviewQueueResponse( service="orquestrador-admin", queue_mode=payload["queue_mode"], message=payload["message"], items=payload["items"], supported_statuses=payload["supported_statuses"], ) @router.get( "/publications", response_model=AdminToolPublicationListResponse, ) def panel_tool_publications( service: ToolManagementService = Depends(get_tool_management_service), _current_staff: AuthenticatedStaffPrincipal = Depends( require_panel_admin_permission(AdminPermission.PUBLISH_TOOLS) ), ): payload = service.build_publications_payload() return AdminToolPublicationListResponse( service="orquestrador-admin", source=payload["source"], target_service=payload["target_service"], publications=payload["publications"], ) def _build_panel_actions(settings: AdminSettings) -> list[AdminToolManagementActionResponse]: return [ AdminToolManagementActionResponse( key="overview", label="Overview web de tools", href=_build_prefixed_path(settings.admin_api_prefix, "/panel/tools/overview"), required_permission=AdminPermission.MANAGE_TOOL_DRAFTS, description="Snapshot do dominio de tools pronto para leitura no painel.", ), AdminToolManagementActionResponse( key="contracts", label="Contratos web de tools", href=_build_prefixed_path(settings.admin_api_prefix, "/panel/tools/contracts"), required_permission=AdminPermission.MANAGE_TOOL_DRAFTS, description="Base contratual para a tela de revisao e aprovacao.", ), AdminToolManagementActionResponse( key="draft_intake", label="Pre-cadastro web de tool", href=_build_prefixed_path(settings.admin_api_prefix, "/panel/tools/drafts/intake"), required_permission=AdminPermission.MANAGE_TOOL_DRAFTS, description="Valida e persiste o draft diretamente na sessao web do painel.", ), AdminToolManagementActionResponse( key="review_queue", label="Fila web de revisao", href=_build_prefixed_path(settings.admin_api_prefix, "/panel/tools/review-queue"), required_permission=AdminPermission.REVIEW_TOOL_GENERATIONS, description="Leitura da fila de revisao sob a sessao web do painel.", ), AdminToolManagementActionResponse( key="publications", label="Publicacoes web", href=_build_prefixed_path(settings.admin_api_prefix, "/panel/tools/publications"), required_permission=AdminPermission.PUBLISH_TOOLS, description="Catalogo de tools ativas e prontas para ativacao no produto.", ), ] def _build_prefixed_path(api_prefix: str, path: str) -> str: normalized_prefix = api_prefix.rstrip("/") normalized_path = path if path.startswith("/") else f"/{path}" if not normalized_prefix: return normalized_path if normalized_path == "/": return f"{normalized_prefix}/" return f"{normalized_prefix}{normalized_path}"