from fastapi import APIRouter, Depends, HTTPException, Query, BackgroundTasks from typing import List, Optional, Dict, Any from datetime import datetime, date import structlog from app.schemas.forecast import ( ForecastRequest, ForecastResponse, BatchForecastRequest, ForecastPerformanceResponse ) from app.services.forecast_service import ForecastService from app.services.messaging import publish_forecast_generated # Import unified authentication from shared.auth.decorators import ( get_current_user_dep, get_current_tenant_id_dep ) router = APIRouter(prefix="/forecasts", tags=["forecasting"]) logger = structlog.get_logger() @router.post("/generate", response_model=ForecastResponse) async def generate_forecast( request: ForecastRequest, background_tasks: BackgroundTasks, tenant_id: str = Depends(get_current_tenant_id_dep), current_user: Dict[str, Any] = Depends(get_current_user_dep), ): """Generate forecast for products""" try: logger.info("Generating forecast", tenant_id=tenant_id, user_id=current_user["user_id"], products=len(request.products) if request.products else "all") forecast_service = ForecastService() # Ensure products belong to tenant if request.products: valid_products = await forecast_service.validate_products( tenant_id, request.products ) if len(valid_products) != len(request.products): raise HTTPException( status_code=400, detail="Some products not found or not accessible" ) # Generate forecast forecast = await forecast_service.generate_forecast( tenant_id=tenant_id, request=request, user_id=current_user["user_id"] ) # Publish event background_tasks.add_task( publish_forecast_generated, forecast_id=forecast.id, tenant_id=tenant_id, user_id=current_user["user_id"] ) return forecast except HTTPException: raise except Exception as e: logger.error("Failed to generate forecast", error=str(e)) raise HTTPException(status_code=500, detail=str(e))