from typing import Optional, Any from domain.training.weekly_snapshot import WeeklySnapshot from domain.training.weekly_trend import WeeklyTrend from domain.runner_positioning import RunnerPositioning, TrainingPhase from domain.training.training_recommendation import TrainingRecommendation from _app.presentation.ui_text import get_text class RecommendationService: """ Stateless service to generate training recommendations based on positioning. """ def generate( self, snapshot: WeeklySnapshot, trend: WeeklyTrend, positioning: Any, # Can be RunnerPositioning or WeeklyPositioning language: str = "en" ) -> TrainingRecommendation: """ Pure rule-based logic to map positioning to training focus and session types. """ # Mapping from positioning focus or status # Handle both Domain (RunnerPositioning) and Application (WeeklyPositioning) models if hasattr(positioning, "recommended_focus"): focus_val = positioning.recommended_focus else: # Fallback for WeeklyPositioning (Application Layer) status_map = { "CONSTRUCTIVE_ADAPTATION": "INTENSITY", "PRODUCTIVE_LOAD": "CONSISTENCY", "STRAIN": "RECOVERY", "PLATEAU": "MAINTENANCE" } focus_val = status_map.get(getattr(positioning, "status", ""), "MAINTENANCE") focus_key = focus_val.lower() # Initial recommendation mapping as per requirements: # Building Momentum (CONSTRUCTIVE_ADAPTATION) -> introduce_intensity / tempo_intervals # Maintaining Consistency (PRODUCTIVE_LOAD) -> build_endurance / long_run # Recovery (STRAIN) -> protect_recovery / easy_run # Default -> maintain_consistency mapping = { "RECOVERY": { "focus": "protect_recovery", "session_type": "easy_run", "confidence": 0.9 }, "CONSISTENCY": { "focus": "build_endurance", "session_type": "long_run", "confidence": 0.8 }, "INTENSITY": { "focus": "introduce_intensity", "session_type": "tempo_intervals", "confidence": 0.85 }, "MAINTENANCE": { "focus": "maintain_consistency", "session_type": "steady_run", "confidence": 0.75 } } rec_data = mapping.get(focus_val, { "focus": "maintain_consistency", "session_type": "steady_run", "confidence": 0.5 }) # Resolve localized description description = get_text(f"rec_desc_{rec_data['focus']}", language) return TrainingRecommendation( focus=get_text(f"rec_focus_{rec_data['focus']}", language), session_type=get_text(f"rec_session_{rec_data['session_type']}", language), description=description, confidence=rec_data["confidence"] )