using Server.WatchBody.Core.Dal.Src.Domain; using Server.WatchBody.Core.Dal.Src.Repository; namespace Server.WatchBody.Import; /// /// Запись фактов в src.workout (spec 02 m06): дедуп по fit_file_id, /// сопоставление телефонной тренировке ± 15 минут (Ф-8.4), иначе /// строка «только .fit». 🛡 Телефонные поля не меняются; записи только /// в facts_json/avg_hr/hr_recovery_s/fit_file_id. /// public class WorkoutImporter( IWorkoutRepository workouts, decimal restingHrSitting = 90) { public Guid Import(int athleteId, ActivityFacts facts) { var day = DateOnly.FromDateTime(facts.StartedAt); var candidates = workouts.Select(new WorkoutFilter { AthleteId = athleteId, DateFrom = day.AddDays(-1), DateTo = day.AddDays(1), }).ToList(); // 1. дедуп: тот же fit_file_id — пропуск (🛡3) var sameFile = candidates.FirstOrDefault(w => w.FitFileId == facts.FitFileId); if (sameFile != null) return sameFile.Id; // 2. сопоставление: ближайшая без fit_file_id в окне ± 15 минут var match = candidates .Where(w => w.FitFileId == null) .Select(w => (workout: w, gap: Math.Abs((w.StartedAt - facts.StartedAt).TotalMinutes))) .Where(x => x.gap <= 15) .OrderBy(x => x.gap) .ThenBy(x => x.workout.Id) .FirstOrDefault(); if (match.workout != null) { var existing = match.workout; workouts.Update(athleteId, new Workout { Id = existing.Id, AthleteId = athleteId, ProgramVersionId = existing.ProgramVersionId, StartedAt = existing.StartedAt, EndedAt = existing.EndedAt, Status = existing.Status, SessionKind = existing.SessionKind, AvgHr = facts.AvgHr ?? existing.AvgHr, FactsJson = facts.FactsJson, FitFileId = facts.FitFileId, HrRecoveryS = facts.HrRecoveryS ?? existing.HrRecoveryS, Sets = [], Commands = [], }); return existing.Id; } // 3. строка «только .fit» (uuid генерирует сервер, Р2-Б); // workout_insert fit-полей не принимает — вставка + дозакрытие // (как sync, errata m02) var id = Guid.NewGuid(); workouts.Insert(athleteId, new Workout { Id = id, AthleteId = athleteId, StartedAt = facts.StartedAt, Status = "finished", SessionKind = "normal", Sets = [], Commands = [], }); workouts.Update(athleteId, new Workout { Id = id, AthleteId = athleteId, StartedAt = facts.StartedAt, Status = "finished", SessionKind = "normal", AvgHr = facts.AvgHr, FactsJson = facts.FactsJson, FitFileId = facts.FitFileId, HrRecoveryS = facts.HrRecoveryS, Sets = [], Commands = [], }); return id; } }