/** * Forecasting hook for managing demand forecasting and ML models */ import { useState, useEffect, useCallback } from 'react'; import { ForecastingService } from '../../services/api/forecasting.service'; import { ForecastModel, ForecastModelCreate, ForecastModelUpdate, ForecastPrediction, ForecastPredictionCreate, ForecastBatch, ModelTraining, ModelEvaluation } from '../../types/forecasting.types'; import { ApiResponse, PaginatedResponse, QueryParams } from '../../types/api.types'; interface ForecastingState { models: ForecastModel[]; predictions: ForecastPrediction[]; batches: ForecastBatch[]; trainings: ModelTraining[]; evaluations: ModelEvaluation[]; isLoading: boolean; error: string | null; pagination: { total: number; page: number; pages: number; limit: number; }; } interface ForecastingActions { // Models fetchModels: (params?: QueryParams) => Promise; createModel: (data: ForecastModelCreate) => Promise; updateModel: (id: string, data: ForecastModelUpdate) => Promise; deleteModel: (id: string) => Promise; getModel: (id: string) => Promise; trainModel: (id: string, parameters?: any) => Promise; deployModel: (id: string) => Promise; // Predictions fetchPredictions: (params?: QueryParams) => Promise; createPrediction: (data: ForecastPredictionCreate) => Promise; getPrediction: (id: string) => Promise; generateDemandForecast: (modelId: string, horizon: number, parameters?: any) => Promise; // Batch Predictions fetchBatches: (params?: QueryParams) => Promise; createBatch: (modelId: string, data: any) => Promise; getBatch: (id: string) => Promise; downloadBatchResults: (id: string) => Promise; // Model Training fetchTrainings: (modelId?: string) => Promise; getTraining: (id: string) => Promise; cancelTraining: (id: string) => Promise; // Model Evaluation fetchEvaluations: (modelId?: string) => Promise; createEvaluation: (modelId: string, testData: any) => Promise; getEvaluation: (id: string) => Promise; // Analytics getModelPerformance: (modelId: string, period?: string) => Promise; getAccuracyReport: (modelId: string, startDate?: string, endDate?: string) => Promise; getFeatureImportance: (modelId: string) => Promise; // Utilities clearError: () => void; refresh: () => Promise; } export const useForecasting = (): ForecastingState & ForecastingActions => { const [state, setState] = useState({ models: [], predictions: [], batches: [], trainings: [], evaluations: [], isLoading: false, error: null, pagination: { total: 0, page: 1, pages: 1, limit: 20, }, }); const forecastingService = new ForecastingService(); // Fetch forecast models const fetchModels = useCallback(async (params?: QueryParams) => { setState(prev => ({ ...prev, isLoading: true, error: null })); try { const response = await forecastingService.getModels(params); if (response.success && response.data) { setState(prev => ({ ...prev, models: Array.isArray(response.data) ? response.data : response.data.items || [], pagination: response.data.pagination || prev.pagination, isLoading: false, })); } else { setState(prev => ({ ...prev, isLoading: false, error: response.error || 'Error al cargar modelos de predicción', })); } } catch (error) { setState(prev => ({ ...prev, isLoading: false, error: 'Error de conexión al servidor', })); } }, [forecastingService]); // Create forecast model const createModel = useCallback(async (data: ForecastModelCreate): Promise => { setState(prev => ({ ...prev, error: null })); try { const response = await forecastingService.createModel(data); if (response.success) { await fetchModels(); return true; } else { setState(prev => ({ ...prev, error: response.error || 'Error al crear modelo de predicción', })); return false; } } catch (error) { setState(prev => ({ ...prev, error: 'Error de conexión al servidor', })); return false; } }, [forecastingService, fetchModels]); // Update forecast model const updateModel = useCallback(async (id: string, data: ForecastModelUpdate): Promise => { setState(prev => ({ ...prev, error: null })); try { const response = await forecastingService.updateModel(id, data); if (response.success) { await fetchModels(); return true; } else { setState(prev => ({ ...prev, error: response.error || 'Error al actualizar modelo de predicción', })); return false; } } catch (error) { setState(prev => ({ ...prev, error: 'Error de conexión al servidor', })); return false; } }, [forecastingService, fetchModels]); // Delete forecast model const deleteModel = useCallback(async (id: string): Promise => { setState(prev => ({ ...prev, error: null })); try { const response = await forecastingService.deleteModel(id); if (response.success) { setState(prev => ({ ...prev, models: prev.models.filter(model => model.id !== id), })); return true; } else { setState(prev => ({ ...prev, error: response.error || 'Error al eliminar modelo de predicción', })); return false; } } catch (error) { setState(prev => ({ ...prev, error: 'Error de conexión al servidor', })); return false; } }, [forecastingService]); // Get single forecast model const getModel = useCallback(async (id: string): Promise => { try { const response = await forecastingService.getModel(id); return response.success ? response.data : null; } catch (error) { console.error('Error fetching model:', error); return null; } }, [forecastingService]); // Train forecast model const trainModel = useCallback(async (id: string, parameters?: any): Promise => { setState(prev => ({ ...prev, error: null })); try { const response = await forecastingService.trainModel(id, parameters); if (response.success) { await fetchModels(); return true; } else { setState(prev => ({ ...prev, error: response.error || 'Error al entrenar modelo', })); return false; } } catch (error) { setState(prev => ({ ...prev, error: 'Error de conexión al servidor', })); return false; } }, [forecastingService, fetchModels]); // Deploy forecast model const deployModel = useCallback(async (id: string): Promise => { setState(prev => ({ ...prev, error: null })); try { const response = await forecastingService.deployModel(id); if (response.success) { await fetchModels(); return true; } else { setState(prev => ({ ...prev, error: response.error || 'Error al desplegar modelo', })); return false; } } catch (error) { setState(prev => ({ ...prev, error: 'Error de conexión al servidor', })); return false; } }, [forecastingService, fetchModels]); // Fetch predictions const fetchPredictions = useCallback(async (params?: QueryParams) => { setState(prev => ({ ...prev, isLoading: true, error: null })); try { const response = await forecastingService.getPredictions(params); if (response.success && response.data) { setState(prev => ({ ...prev, predictions: Array.isArray(response.data) ? response.data : response.data.items || [], isLoading: false, })); } else { setState(prev => ({ ...prev, isLoading: false, error: response.error || 'Error al cargar predicciones', })); } } catch (error) { setState(prev => ({ ...prev, isLoading: false, error: 'Error de conexión al servidor', })); } }, [forecastingService]); // Create prediction const createPrediction = useCallback(async (data: ForecastPredictionCreate): Promise => { setState(prev => ({ ...prev, error: null })); try { const response = await forecastingService.createPrediction(data); if (response.success) { await fetchPredictions(); return true; } else { setState(prev => ({ ...prev, error: response.error || 'Error al crear predicción', })); return false; } } catch (error) { setState(prev => ({ ...prev, error: 'Error de conexión al servidor', })); return false; } }, [forecastingService, fetchPredictions]); // Get single prediction const getPrediction = useCallback(async (id: string): Promise => { try { const response = await forecastingService.getPrediction(id); return response.success ? response.data : null; } catch (error) { console.error('Error fetching prediction:', error); return null; } }, [forecastingService]); // Generate demand forecast const generateDemandForecast = useCallback(async (modelId: string, horizon: number, parameters?: any) => { try { const response = await forecastingService.generateDemandForecast(modelId, horizon, parameters); return response.success ? response.data : null; } catch (error) { console.error('Error generating demand forecast:', error); return null; } }, [forecastingService]); // Fetch batch predictions const fetchBatches = useCallback(async (params?: QueryParams) => { try { const response = await forecastingService.getBatches(params); if (response.success && response.data) { setState(prev => ({ ...prev, batches: Array.isArray(response.data) ? response.data : response.data.items || [], })); } } catch (error) { console.error('Error fetching batches:', error); } }, [forecastingService]); // Create batch prediction const createBatch = useCallback(async (modelId: string, data: any): Promise => { try { const response = await forecastingService.createBatch(modelId, data); if (response.success) { await fetchBatches(); return true; } return false; } catch (error) { console.error('Error creating batch:', error); return false; } }, [forecastingService, fetchBatches]); // Get single batch const getBatch = useCallback(async (id: string): Promise => { try { const response = await forecastingService.getBatch(id); return response.success ? response.data : null; } catch (error) { console.error('Error fetching batch:', error); return null; } }, [forecastingService]); // Download batch results const downloadBatchResults = useCallback(async (id: string): Promise => { try { const response = await forecastingService.downloadBatchResults(id); return response.success; } catch (error) { console.error('Error downloading batch results:', error); return false; } }, [forecastingService]); // Fetch model trainings const fetchTrainings = useCallback(async (modelId?: string) => { try { const response = await forecastingService.getTrainings(modelId); if (response.success && response.data) { setState(prev => ({ ...prev, trainings: Array.isArray(response.data) ? response.data : response.data.items || [], })); } } catch (error) { console.error('Error fetching trainings:', error); } }, [forecastingService]); // Get single training const getTraining = useCallback(async (id: string): Promise => { try { const response = await forecastingService.getTraining(id); return response.success ? response.data : null; } catch (error) { console.error('Error fetching training:', error); return null; } }, [forecastingService]); // Cancel model training const cancelTraining = useCallback(async (id: string): Promise => { try { const response = await forecastingService.cancelTraining(id); if (response.success) { await fetchTrainings(); return true; } return false; } catch (error) { console.error('Error canceling training:', error); return false; } }, [forecastingService, fetchTrainings]); // Fetch model evaluations const fetchEvaluations = useCallback(async (modelId?: string) => { try { const response = await forecastingService.getEvaluations(modelId); if (response.success && response.data) { setState(prev => ({ ...prev, evaluations: Array.isArray(response.data) ? response.data : response.data.items || [], })); } } catch (error) { console.error('Error fetching evaluations:', error); } }, [forecastingService]); // Create model evaluation const createEvaluation = useCallback(async (modelId: string, testData: any): Promise => { try { const response = await forecastingService.createEvaluation(modelId, testData); if (response.success) { await fetchEvaluations(modelId); return true; } return false; } catch (error) { console.error('Error creating evaluation:', error); return false; } }, [forecastingService, fetchEvaluations]); // Get single evaluation const getEvaluation = useCallback(async (id: string): Promise => { try { const response = await forecastingService.getEvaluation(id); return response.success ? response.data : null; } catch (error) { console.error('Error fetching evaluation:', error); return null; } }, [forecastingService]); // Get model performance const getModelPerformance = useCallback(async (modelId: string, period?: string) => { try { const response = await forecastingService.getModelPerformance(modelId, period); return response.success ? response.data : null; } catch (error) { console.error('Error fetching model performance:', error); return null; } }, [forecastingService]); // Get accuracy report const getAccuracyReport = useCallback(async (modelId: string, startDate?: string, endDate?: string) => { try { const response = await forecastingService.getAccuracyReport(modelId, startDate, endDate); return response.success ? response.data : null; } catch (error) { console.error('Error fetching accuracy report:', error); return null; } }, [forecastingService]); // Get feature importance const getFeatureImportance = useCallback(async (modelId: string) => { try { const response = await forecastingService.getFeatureImportance(modelId); return response.success ? response.data : null; } catch (error) { console.error('Error fetching feature importance:', error); return null; } }, [forecastingService]); // Clear error const clearError = useCallback(() => { setState(prev => ({ ...prev, error: null })); }, []); // Refresh all data const refresh = useCallback(async () => { await Promise.all([ fetchModels(), fetchPredictions(), fetchBatches(), ]); }, [fetchModels, fetchPredictions, fetchBatches]); // Initialize data on mount useEffect(() => { refresh(); }, []); return { ...state, fetchModels, createModel, updateModel, deleteModel, getModel, trainModel, deployModel, fetchPredictions, createPrediction, getPrediction, generateDemandForecast, fetchBatches, createBatch, getBatch, downloadBatchResults, fetchTrainings, getTraining, cancelTraining, fetchEvaluations, createEvaluation, getEvaluation, getModelPerformance, getAccuracyReport, getFeatureImportance, clearError, refresh, }; };