""" Enterprise forecasting API endpoints """ from fastapi import APIRouter, Depends, HTTPException, Query from typing import Optional from datetime import date import structlog from app.services.enterprise_forecasting_service import EnterpriseForecastingService from shared.auth.tenant_access import verify_tenant_permission_dep from shared.clients import get_forecast_client, get_tenant_client import shared.redis_utils from app.core.config import settings logger = structlog.get_logger() router = APIRouter() # Global Redis client _redis_client = None async def get_forecasting_redis_client(): """Get or create Redis client""" global _redis_client try: if _redis_client is None: _redis_client = await shared.redis_utils.initialize_redis(settings.REDIS_URL) logger.info("Redis client initialized for enterprise forecasting") return _redis_client except Exception as e: logger.warning("Failed to initialize Redis client, enterprise forecasting will work with limited functionality", error=str(e)) return None async def get_enterprise_forecasting_service( redis_client = Depends(get_forecasting_redis_client) ) -> EnterpriseForecastingService: """Dependency injection for EnterpriseForecastingService""" forecast_client = get_forecast_client(settings, "forecasting-service") tenant_client = get_tenant_client(settings, "forecasting-service") return EnterpriseForecastingService( forecast_client=forecast_client, tenant_client=tenant_client, redis_client=redis_client ) @router.get("/tenants/{tenant_id}/forecasting/enterprise/aggregated") async def get_aggregated_forecast( tenant_id: str, start_date: date = Query(..., description="Start date for forecast aggregation"), end_date: date = Query(..., description="End date for forecast aggregation"), product_id: Optional[str] = Query(None, description="Optional product ID to filter by"), enterprise_forecasting_service: EnterpriseForecastingService = Depends(get_enterprise_forecasting_service), verified_tenant: str = Depends(verify_tenant_permission_dep) ): """ Get aggregated forecasts across parent and child tenants """ try: # Check if this tenant is a parent tenant tenant_info = await enterprise_forecasting_service.tenant_client.get_tenant(tenant_id) if tenant_info.get('tenant_type') != 'parent': raise HTTPException( status_code=403, detail="Only parent tenants can access aggregated enterprise forecasts" ) result = await enterprise_forecasting_service.get_aggregated_forecast( parent_tenant_id=tenant_id, start_date=start_date, end_date=end_date, product_id=product_id ) return result except Exception as e: raise HTTPException(status_code=500, detail=f"Failed to get aggregated forecast: {str(e)}") @router.get("/tenants/{tenant_id}/forecasting/enterprise/network-performance") async def get_network_performance_metrics( tenant_id: str, start_date: date = Query(..., description="Start date for metrics"), end_date: date = Query(..., description="End date for metrics"), enterprise_forecasting_service: EnterpriseForecastingService = Depends(get_enterprise_forecasting_service), verified_tenant: str = Depends(verify_tenant_permission_dep) ): """ Get aggregated performance metrics across tenant network """ try: # Check if this tenant is a parent tenant tenant_info = await enterprise_forecasting_service.tenant_client.get_tenant(tenant_id) if tenant_info.get('tenant_type') != 'parent': raise HTTPException( status_code=403, detail="Only parent tenants can access network performance metrics" ) result = await enterprise_forecasting_service.get_network_performance_metrics( parent_tenant_id=tenant_id, start_date=start_date, end_date=end_date ) return result except Exception as e: raise HTTPException(status_code=500, detail=f"Failed to get network performance: {str(e)}")