from fastapi import APIRouter, Depends, HTTPException, status, Query from sqlalchemy.ext.asyncio import AsyncSession import logging from database import get_session, User from core.dependencies import get_current_user from services.sage_gateway import ( SageGatewayService, gateway_response_from_model, ) from schemas import ( SageGatewayCreate, SageGatewayUpdate, SageGatewayResponse, SageGatewayListResponse, SageGatewayHealthCheck, SageGatewayTestRequest, SageGatewayStatsResponse, CurrentGatewayInfo, ) from config import settings logger = logging.getLogger(__name__) router = APIRouter(prefix="/sage-gateways", tags=["Sage Gateways"]) @router.post( "", response_model=SageGatewayResponse, status_code=status.HTTP_201_CREATED ) async def create_gateway( data: SageGatewayCreate, session: AsyncSession = Depends(get_session), user: User = Depends(get_current_user), ): service = SageGatewayService(session) gateway = await service.create(user.id, data.model_dump()) logger.info(f"Gateway créée: {gateway.name} par {user.email}") return SageGatewayResponse(**gateway_response_from_model(gateway)) @router.get("", response_model=SageGatewayListResponse) async def list_gateways( include_deleted: bool = Query(False, description="Inclure les gateways supprimées"), session: AsyncSession = Depends(get_session), user: User = Depends(get_current_user), ): service = SageGatewayService(session) gateways = await service.list_for_user(user.id, include_deleted) active = await service.get_active_gateway(user.id) items = [SageGatewayResponse(**gateway_response_from_model(g)) for g in gateways] return SageGatewayListResponse( items=items, total=len(items), active_gateway=SageGatewayResponse(**gateway_response_from_model(active)) if active else None, using_fallback=active is None, ) @router.get("/current", response_model=CurrentGatewayInfo) async def get_current_gateway( session: AsyncSession = Depends(get_session), user: User = Depends(get_current_user), ): service = SageGatewayService(session) url, token, gateway_id = await service.get_effective_gateway_config(user.id) if gateway_id: gateway = await service.get_by_id(gateway_id, user.id) return CurrentGatewayInfo( source="user_config", gateway_id=gateway_id, gateway_name=gateway.name if gateway else None, gateway_url=url, is_healthy=gateway.last_health_status if gateway else None, user_id=user.id, ) else: return CurrentGatewayInfo( source="fallback", gateway_id=None, gateway_name="Configuration .env (défaut)", gateway_url=url, is_healthy=None, user_id=user.id, ) @router.get("/stats", response_model=SageGatewayStatsResponse) async def get_gateway_stats( session: AsyncSession = Depends(get_session), user: User = Depends(get_current_user), ): service = SageGatewayService(session) stats = await service.get_stats(user.id) return SageGatewayStatsResponse(**stats) @router.get("/{gateway_id}", response_model=SageGatewayResponse) async def get_gateway( gateway_id: str, session: AsyncSession = Depends(get_session), user: User = Depends(get_current_user), ): service = SageGatewayService(session) gateway = await service.get_by_id(gateway_id, user.id) if not gateway: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Gateway {gateway_id} introuvable", ) return SageGatewayResponse(**gateway_response_from_model(gateway)) @router.put("/{gateway_id}", response_model=SageGatewayResponse) async def update_gateway( gateway_id: str, data: SageGatewayUpdate, session: AsyncSession = Depends(get_session), user: User = Depends(get_current_user), ): service = SageGatewayService(session) update_data = {k: v for k, v in data.model_dump().items() if v is not None} if not update_data: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Aucun champ à modifier" ) gateway = await service.update(gateway_id, user.id, update_data) if not gateway: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Gateway {gateway_id} introuvable", ) logger.info(f"Gateway mise à jour: {gateway.name} par {user.email}") return SageGatewayResponse(**gateway_response_from_model(gateway)) @router.delete("/{gateway_id}") async def delete_gateway( gateway_id: str, hard_delete: bool = Query(False, description="Suppression définitive"), session: AsyncSession = Depends(get_session), user: User = Depends(get_current_user), ): service = SageGatewayService(session) success = await service.delete(gateway_id, user.id, hard_delete) if not success: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Gateway {gateway_id} introuvable", ) logger.info( f"Gateway supprimée: {gateway_id} par {user.email} (hard={hard_delete})" ) return { "success": True, "message": f"Gateway supprimée {'définitivement' if hard_delete else '(soft delete)'}", } @router.post("/{gateway_id}/activate", response_model=SageGatewayResponse) async def activate_gateway( gateway_id: str, session: AsyncSession = Depends(get_session), user: User = Depends(get_current_user), ): service = SageGatewayService(session) gateway = await service.activate(gateway_id, user.id) if not gateway: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Gateway {gateway_id} introuvable", ) logger.info(f"Gateway activée: {gateway.name} par {user.email}") return SageGatewayResponse(**gateway_response_from_model(gateway)) @router.post("/{gateway_id}/deactivate", response_model=SageGatewayResponse) async def deactivate_gateway( gateway_id: str, session: AsyncSession = Depends(get_session), user: User = Depends(get_current_user), ): service = SageGatewayService(session) gateway = await service.deactivate(gateway_id, user.id) if not gateway: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Gateway {gateway_id} introuvable", ) logger.info(f"Gateway désactivée: {gateway.name} - fallback actif") return SageGatewayResponse(**gateway_response_from_model(gateway)) @router.post("/deactivate-all") async def deactivate_all_gateways( session: AsyncSession = Depends(get_session), user: User = Depends(get_current_user), ): service = SageGatewayService(session) await service._deactivate_all_for_user(user.id) await session.commit() logger.info( f"Toutes les gateways désactivées pour {user.email} - fallback .env actif" ) return { "success": True, "message": "Toutes les gateways désactivées. Le fallback .env est maintenant utilisé.", "fallback_url": settings.sage_gateway_url, } @router.post("/{gateway_id}/health-check", response_model=SageGatewayHealthCheck) async def check_gateway_health( gateway_id: str, session: AsyncSession = Depends(get_session), user: User = Depends(get_current_user), ): from datetime import datetime service = SageGatewayService(session) gateway = await service.get_by_id(gateway_id, user.id) if not gateway: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Gateway {gateway_id} introuvable", ) result = await service.health_check(gateway_id, user.id) return SageGatewayHealthCheck( gateway_id=gateway_id, gateway_name=gateway.name, status=result.get("status", "unknown"), response_time_ms=result.get("response_time_ms"), sage_version=result.get("sage_version"), error=result.get("error"), checked_at=datetime.now(), ) @router.post("/test", response_model=dict) async def test_gateway_config( data: SageGatewayTestRequest, user: User = Depends(get_current_user), session: AsyncSession = Depends(get_session), ): service = SageGatewayService(session) result = await service.test_gateway(data.gateway_url, data.gateway_token) return {"tested_url": data.gateway_url, "result": result} @router.post("/health-check-all") async def check_all_gateways_health( session: AsyncSession = Depends(get_session), user: User = Depends(get_current_user), ): service = SageGatewayService(session) gateways = await service.list_for_user(user.id) results = [] for gateway in gateways: result = await service.health_check(gateway.id, user.id) results.append( { "gateway_id": gateway.id, "gateway_name": gateway.name, "is_active": gateway.is_active, **result, } ) healthy_count = sum(1 for r in results if r.get("status") == "healthy") return { "total": len(results), "healthy": healthy_count, "unhealthy": len(results) - healthy_count, "results": results, } @router.get("/fallback/info") async def get_fallback_info( user: User = Depends(get_current_user), ): return { "source": ".env", "gateway_url": settings.sage_gateway_url, "token_configured": bool(settings.sage_gateway_token), "token_preview": f"****{settings.sage_gateway_token[-4:]}" if settings.sage_gateway_token else None, "description": "Configuration par défaut utilisée quand aucune gateway utilisateur n'est active", }