import 'package:get/get.dart'; import '../models/gps_coordinate.dart'; import '../models/workout.dart'; import '../models/workout_segment.dart'; import '../utils/geo_utils.dart'; /// خدمة التحليل الذكي (Smart Analytics Service) /// مسؤولة عن تقسيم المسار إلى أجزاء، كشف التوقفات، وتحليل أنماط الأداء. class AnalyticsService extends GetxService { /// تحليل المسار وتقسيمه إلى أجزاء (Segments) /// يعتمد على تغيرات السرعة، الارتفاع، أو الاتجاه. List analyzeSegments(List coords, WorkoutType type) { if (coords.length < 5) return []; List segments = []; int startIdx = 0; int segmentCounter = 0; // 1. تحديد مرحلة الإحماء (Warm-up) // نعتبر أول 10% من النقاط أو أول 500 متر إحماء إذا كانت السرعة متدرجة int warmupEnd = (coords.length * 0.1).toInt().clamp(5, 50); segments.add(_createSegment(coords, 0, warmupEnd, segmentCounter++, SegmentType.warmup)); startIdx = warmupEnd; // 2. تحليل النقاط الوسطى لكشف التوقفات أو التسارعات for (int i = startIdx + 1; i < coords.length - 5; i++) { final current = coords[i]; final prev = coords[i - 1]; // كشف التوقف (Stop detection) // إذا كانت السرعة شبه صفرية لمسافة معينة if (current.speed != null && current.speed! < 0.3) { int stopEnd = i; while (stopEnd < coords.length - 1 && (coords[stopEnd].speed ?? 0) < 0.3 && stopEnd - i < 20) { // توقف بحد أقصى 20 نقطة لتجنب المقاطع الضخمة stopEnd++; } if (stopEnd - i > 3) { // توقف حقيقي لأكثر من 10 ثواني تقريباً // إغلاق المقطع السابق إذا كان هناك مسافة if (i > startIdx) { segments.add(_createSegment(coords, startIdx, i, segmentCounter++, SegmentType.main)); } segments.add(_createSegment(coords, i, stopEnd, segmentCounter++, SegmentType.stop)); i = stopEnd; startIdx = i; } } // كشف الميول (Elevation detection) // يمكن التوسع هنا لكشف uphill/downhill } // 3. تحديد مرحلة التبريد (Cool-down) int cooldownStart = (coords.length * 0.9).toInt(); if (cooldownStart > startIdx) { segments.add(_createSegment(coords, startIdx, cooldownStart, segmentCounter++, SegmentType.main)); segments.add(_createSegment(coords, cooldownStart, coords.length - 1, segmentCounter++, SegmentType.cooldown)); } else { segments.add(_createSegment(coords, startIdx, coords.length - 1, segmentCounter++, SegmentType.main)); } return segments; } WorkoutSegment _createSegment(List coords, int start, int end, int index, SegmentType type) { double dist = 0; double maxSpd = 0; double sumSpd = 0; double elevChange = 0; for (int i = start + 1; i <= end; i++) { dist += GeoUtils.haversineDistance( coords[i-1].latitude, coords[i-1].longitude, coords[i].latitude, coords[i].longitude ); double s = coords[i].speed ?? 0; if (s > maxSpd) maxSpd = s; sumSpd += s; if (coords[i].altitude != null && coords[i-1].altitude != null) { elevChange += (coords[i].altitude! - coords[i-1].altitude!); } } int duration = coords[end].timestamp.difference(coords[start].timestamp).inSeconds; return WorkoutSegment( segmentIndex: index, type: type, distanceMeters: dist, durationSeconds: duration, avgSpeedMps: duration > 0 ? dist / duration : 0, maxSpeedMps: maxSpd, elevationChange: elevChange, startCoordIndex: start, endCoordIndex: end, ); } /// حساب "التقارير الذكية" /// مثال: "سرعتك في أول 2 كم تحسنت بنسبة 12%" String generateInsight(List history) { if (history.length < 2) return "ابدأ تمرينك الأول للحصول على تحليلات!"; // منطق بسيط للمقارنة بين آخر تمرينين final latest = history[0]; final previous = history[1]; if (latest.avgSpeedMps > previous.avgSpeedMps) { double diff = ((latest.avgSpeedMps - previous.avgSpeedMps) / previous.avgSpeedMps) * 100; return "أداء رائع! سرعتك المتوسطة تحسنت بنسبة ${diff.toStringAsFixed(1)}% مقارنة بآخر مرة."; } return "استمر في التدريب! الاستمرارية هي مفتاح التطور."; } }