// AITrainingPlanGenerator.swift // AI-powered personalized training plan generation for Nessa import Foundation import Combine /// AI Training Plan Generator /// Generates personalized workout plans based on user profile, fitness level, /// workout history, and goals @MainActor class AITrainingPlanGenerator { // MARK: - Properties private let userService: UserServiceProtocol private let workoutService: WorkoutServiceProtocol private let analyticsService: AnalyticsServiceProtocol private let rateLimiter = RateLimiter(maxRequests: 3, interval: 300) // 3 requests per 5 minutes private var cancellables = Set() // MARK: - Initialization init(userService: UserServiceProtocol = UserService.shared, workoutService: WorkoutServiceProtocol = WorkoutService.shared, analyticsService: AnalyticsServiceProtocol = AnalyticsService.shared) { self.userService = userService self.workoutService = workoutService self.analyticsService = analyticsService } // MARK: - Public Methods /// Generate a personalized training plan for the user /// - Parameter goals: User's fitness goals (strength, endurance, weight loss, etc.) /// - Parameter duration: Preferred weekly training duration in hours /// - Parameter difficulty: Preferred difficulty level /// - Returns: Generated training plan func generatePlan(goals: [GoalType] = [], duration: Double = 5.0, difficulty: DifficultyLevel = .moderate) async throws -> TrainingPlan { guard rateLimiter.isAllowed() else { throw RateLimitError.rateLimited } let userProfile = await analyzeUserProfile() let progressData = await analyzeProgress() let recommendations = await generateRecommendations( profile: userProfile, goals: goals, currentLevel: userProfile.fitnessLevel, progress: progressData ) return TrainingPlan( id: UUID().uuidString, userProfile: userProfile, recommendations: recommendations, duration: duration, difficulty: difficulty, generatedAt: Date(), version: 1 ) } /// Analyze user profile and determine fitness level func analyzeUserProfile() async throws -> UserProfile { guard let user = await userService.currentUser else { throw ProfileAnalysisError.noUserProfile } let workoutHistory = await workoutService.getUserWorkoutHistory(limit: 50) let performanceMetrics = await analyticsService.calculatePerformanceMetrics() // Determine fitness level based on workout frequency, intensity, and consistency let workoutFrequency = Double(workoutHistory.count) / 30.0 // workouts per month let avgIntensity = workoutHistory.map { $0.intensity }.average ?? 0.5 let consistencyScore = calculateConsistency(workoutHistory) let fitnessLevel: FitnessLevel if workoutFrequency >= 4 && avgIntensity >= 0.7 && consistencyScore >= 0.8 { fitnessLevel = .advanced } else if workoutFrequency >= 2 && avgIntensity >= 0.5 && consistencyScore >= 0.6 { fitnessLevel = .intermediate } else if workoutFrequency >= 1 && avgIntensity >= 0.3 && consistencyScore >= 0.4 { fitnessLevel = .beginner } else { fitnessLevel = .absoluteBeginner } return UserProfile( userId: user.id, name: user.name, fitnessLevel: fitnessLevel, workoutFrequency: workoutFrequency, avgIntensity: avgIntensity, consistencyScore: consistencyScore, preferences: user.preferences ?? [], injuries: user.injuries ?? [] ) } /// Analyze user's progress and trends func analyzeProgress() async throws -> ProgressAnalysis { let recentWorkouts = await workoutService.getRecentWorkouts(limit: 20) let performanceTrends = await analyticsService.calculateTrends(recentWorkouts: recentWorkouts) return ProgressAnalysis( totalWorkouts: recentWorkouts.count, avgDuration: recentWorkouts.map { $0.duration }.average ?? 0, avgCalories: recentWorkouts.map { $0.caloriesBurned }.average ?? 0, improvementRate: performanceTrends.improvementRate, consistencyStreak: performanceTrends.streak, plateauDetected: performanceTrends.plateauDetected, injuryRisk: performanceTrends.injuryRisk ) } /// Generate personalized recommendations func generateRecommendations(profile: UserProfile, goals: [GoalType], currentLevel: FitnessLevel, progress: ProgressAnalysis) async throws -> [Recommendation] { var recommendations: [Recommendation] = [] // Goal-based recommendations for goal in goals { switch goal { case .strength: recommendations.append(Recommendation( type: .workout, title: "Strength Training Focus", description: "Incorporate 2-3 strength sessions per week with progressive overload", priority: .high, estimatedDuration: 60.0, frequency: 2 )) case .endurance: recommendations.append(Recommendation( type: .workout, title: "Endurance Building, description: "Longer duration cardio with progressive distance increases", priority: .high, estimatedDuration: 90.0, frequency: 3 )) case .weightLoss: recommendations.append(Recommendation( type: .workout, title: "HIIT and Cardio Mix", description: "High-intensity intervals mixed with moderate cardio", priority: .high, estimatedDuration: 45.0, frequency: 4 )) case .flexibility: recommendations.append(Recommendation( type: .workout, title: "Flexibility and Mobility", description: "Daily stretching and mobility sessions", priority: .medium, estimatedDuration: 20.0, frequency: 1 )) } } // Level-appropriate recommendations switch currentLevel { case .absoluteBeginner: recommendations.append(Recommendation( type: .tutorial, title: "Beginner Foundation Course", description: "Complete the 4-week foundation program to build basic fitness", priority: .high, estimatedDuration: 30.0, frequency: 3 )) case .beginner: recommendations.append(Recommendation( type: .workout, title: "Progressive Challenge Program", description: "Gradually increase intensity each week", priority: .medium, estimatedDuration: 45.0, frequency: 3 )) case .intermediate: recommendations.append(Recommendation( type: .workout, title: "Advanced Challenge Series", description: "Introduce varied workout types and increased intensity", priority: .medium, estimatedDuration: 60.0, frequency: 3 )) case .advanced: recommendations.append(Recommendation( type: .workout, title: "Elite Performance Program", description: "Specialized training based on specific goals", priority: .high, estimatedDuration: 90.0, frequency: 4 )) } // Progress-based adjustments if progress.plateauDetected { recommendations.append(Recommendation( type: .adjustment, title: "Break Through Plateau", description: "Change workout variety and intensity to break through plateau", priority: .high, estimatedDuration: 0.0, frequency: 0 )) } if progress.injuryRisk > 0.7 { recommendations.append(Recommendation( type: .caution, title: "Injury Prevention Focus", description: "Reduce intensity and focus on form; consult a professional", priority: .critical, estimatedDuration: 0.0, frequency: 0 )) } // Filter by user preferences and injuries recommendations = recommendations.filter { rec in !rec.title.contains("Injury Prevention") || (profile.injuries?.contains($0.title.lowercased()) ?? false) } // Sort by priority return recommendations.sorted { $0.priority > $1.priority } } // MARK: - Helper Methods private func calculateConsistency(_ workouts: [Workout]) -> Double { guard workouts.count > 0 else { return 0 } let workoutDates = workouts.map { $0.date } let uniqueWeeks = Set(workoutDates.map { Calendar.current.component(.weekOfYear, from: $0) }) let weeksActive = Calendar.current.dateComponents([.calendar], from: workoutDates.first!, to: workoutDates.last!).weekOfYear ?? 0 guard weeksActive > 0 else { return 0 } return Double(uniqueWeeks.count) / Double(weeksActive) } private extension Double { var average: Double { guard count > 0 else { return 0 } return sum / count } } // MARK: - Private Types private struct UserProfile { let userId: String let name: String let fitnessLevel: FitnessLevel let workoutFrequency: Double let avgIntensity: Double let consistencyScore: Double let preferences: [String] let injuries: [String] } private struct ProgressAnalysis { let totalWorkouts: Int let avgDuration: Double let avgCalories: Double let improvementRate: Double let consistencyStreak: Int let plateauDetected: Bool let injuryRisk: Double } private struct Recommendation { let type: RecommendationType let title: String let description: String let priority: Priority let estimatedDuration: Double let frequency: Int } private struct TrainingPlan { let id: String let userProfile: UserProfile let recommendations: [Recommendation] let duration: Double let difficulty: DifficultyLevel let generatedAt: Date let version: Int } // MARK: - Enums private enum GoalType { case strength case endurance case weightLoss case flexibility } private enum DifficultyLevel { case easy case moderate case hard case elite } private enum FitnessLevel { case absoluteBeginner case beginner case intermediate case advanced } private enum Priority { case critical > case high > case medium > case low } private enum RecommendationType { case workout case tutorial case adjustment case caution } // MARK: - Errors private enum RateLimitError: Error { case rateLimited } private enum ProfileAnalysisError: Error { case noUserProfile case insufficientData } }