public async Task <SyncResult> SyncAsync(int numWorkouts)
        {
            using var timer    = SyncHistogram.NewTimer();
            using var activity = Tracing.Trace($"{nameof(SyncService)}.{nameof(SyncAsync)}")
                                 .WithTag("numWorkouts", numWorkouts.ToString());

            ICollection <RecentWorkout> recentWorkouts;
            var syncTime = await _db.GetSyncStatusAsync();

            syncTime.LastSyncTime = DateTime.Now;

            try
            {
                recentWorkouts = await _pelotonService.GetRecentWorkoutsAsync(numWorkouts);
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "Failed to fetch recent workouts from Peleoton.");
                activity?.AddTag("exception.message", ex.Message);
                activity?.AddTag("exception.stacktrace", ex.StackTrace);

                await _db.UpsertSyncStatusAsync(syncTime);

                var response = new SyncResult();
                response.SyncSuccess            = false;
                response.PelotonDownloadSuccess = false;
                response.Errors.Add(new ErrorResponse()
                {
                    Message = "Failed to fetch recent workouts from Peloton. Check logs for more details."
                });
                return(response);
            }

            var completedWorkouts = recentWorkouts
                                    .Where(w =>
            {
                var shouldKeep = w.Status == "COMPLETE";
                if (shouldKeep)
                {
                    return(true);
                }

                _logger.Debug("Skipping in progress workout. {@WorkoutId} {@WorkoutStatus} {@WorkoutType} {@WorkoutTitle}", w.Id, w.Status, w.Fitness_Discipline, w.Title);
                return(false);
            })
                                    .Select(r => r.Id)
                                    .ToList();

            _logger.Debug("Total workouts found after filtering out InProgress: {@FoundWorkouts}", completedWorkouts.Count());
            activity?.AddTag("workouts.completed", completedWorkouts.Count());

            var result = await SyncAsync(completedWorkouts, _config.Peloton.ExcludeWorkoutTypes);

            if (result.SyncSuccess)
            {
                syncTime.LastSuccessfulSyncTime = DateTime.Now;
            }

            await _db.UpsertSyncStatusAsync(syncTime);

            return(result);
        }
        public async Task <SyncResult> SyncAsync(ICollection <string> workoutIds, ICollection <WorkoutType>?exclude = null)
        {
            using var timer    = SyncHistogram.NewTimer();
            using var activity = Tracing.Trace($"{nameof(SyncService)}.{nameof(SyncAsync)}.ByWorkoutIds");

            var response       = new SyncResult();
            var recentWorkouts = workoutIds.Select(w => new RecentWorkout()
            {
                Id = w
            }).ToList();

            P2GWorkout[] workouts = { };
            try
            {
                workouts = await _pelotonService.GetWorkoutDetailsAsync(recentWorkouts);

                response.PelotonDownloadSuccess = true;
            }
            catch (Exception e)
            {
                _logger.Error(e, "Failed to download workouts from Peleoton.");
                response.SyncSuccess            = false;
                response.PelotonDownloadSuccess = false;
                response.Errors.Add(new ErrorResponse()
                {
                    Message = "Failed to download workouts from Peloton. Check logs for more details."
                });
                return(response);
            }

            var filteredWorkouts = workouts.Where(w =>
            {
                if (exclude is null || exclude.Count == 0)
                {
                    return(true);
                }

                if (exclude.Contains(w.WorkoutType))
                {
                    _logger.Debug("Skipping excluded workout type. {@WorkoutId} {@WorkoutType}", w.Workout.Id, w.WorkoutType);
                    return(false);
                }

                return(true);
            });

            activity?.AddTag("workouts.filtered", filteredWorkouts.Count());
            _logger.Debug("Number of workouts to convert after filtering InProgress: {@NumWorkouts}", filteredWorkouts.Count());

            try
            {
                Parallel.ForEach(filteredWorkouts, (workout) =>
                {
                    Parallel.ForEach(_converters, (converter) =>
                    {
                        converter.Convert(workout);
                    });
                });

                response.ConversionSuccess = true;
            }
            catch (Exception e)
            {
                _logger.Error(e, "Failed to convert workouts to FIT format.");

                response.SyncSuccess       = false;
                response.ConversionSuccess = false;
                response.Errors.Add(new ErrorResponse()
                {
                    Message = "Failed to convert workouts to FIT format. Check logs for more details."
                });
                return(response);
            }

            try
            {
                await _garminUploader.UploadToGarminAsync();

                response.UploadToGarminSuccess = true;
            }
            catch (Exception e)
            {
                _logger.Error(e, "GUpload returned an error code. Failed to upload workouts.");
                _logger.Warning("GUpload failed to upload files. You can find the converted files at {@Path} \n You can manually upload your files to Garmin Connect, or wait for P2G to try again on the next sync job.", _config.App.OutputDirectory);

                response.SyncSuccess           = false;
                response.UploadToGarminSuccess = false;
                response.Errors.Add(new ErrorResponse()
                {
                    Message = "Failed to upload to Garmin Connect. Check logs for more details."
                });
                return(response);
            } finally
            {
                _fileHandler.Cleanup(_config.App.DownloadDirectory);
                _fileHandler.Cleanup(_config.App.UploadDirectory);
                _fileHandler.Cleanup(_config.App.WorkingDirectory);
            }

            response.SyncSuccess = true;
            return(response);
        }