import Foundation import SwiftData /// Builds the bundled machine-based starter routine (Upper Body / Core / Lower /// Body). Written on demand (never auto-seeded) through the SyncEngine — an empty /// cache at launch can't be told apart from an iCloud library that simply hasn't /// downloaded yet. enum SplitSeeder { /// One starter exercise: name plus its default starting weight (lbs). private struct SeedExercise { let name: String let weight: Int } /// One starter split: visual theme plus its ordered exercises. private struct SeedSplit { let name: String let color: String let icon: String let exercises: [SeedExercise] } /// Sets/reps shared by every starter exercise. private static let defaultSets = 4 private static let defaultReps = 10 /// Starter splits in display order, with sensible machine starting weights. /// Users adjust weights from the exercise screen. private static let starterSplits: [SeedSplit] = [ SeedSplit(name: "Upper Body", color: "blue", icon: "figure.strengthtraining.traditional", exercises: [ SeedExercise(name: "Lat Pull Down", weight: 110), SeedExercise(name: "Tricep Press", weight: 100), SeedExercise(name: "Chest Press", weight: 40), SeedExercise(name: "Seated Row", weight: 90), ]), SeedSplit(name: "Core", color: "orange", icon: "figure.core.training", exercises: [ SeedExercise(name: "Abdominal", weight: 0), SeedExercise(name: "Rotary", weight: 0), ]), SeedSplit(name: "Lower Body", color: "green", icon: "figure.run", exercises: [ SeedExercise(name: "Abductor", weight: 140), SeedExercise(name: "Adductor", weight: 140), SeedExercise(name: "Leg Press", weight: 160), SeedExercise(name: "Leg Curl", weight: 70), ]), ] /// Builds the default split documents (fresh ULIDs each call). static func defaultSplitDocuments() -> [SplitDocument] { starterSplits.enumerated().map { order, split in let exercises = split.exercises.enumerated().map { idx, item in ExerciseDocument( id: ULID.make(), name: item.name, order: idx, sets: defaultSets, reps: defaultReps, weight: item.weight, loadType: LoadType.weight.rawValue, durationSeconds: 0, weightLastUpdated: nil, weightReminderWeeks: 2 ) } return SplitDocument( schemaVersion: SplitDocument.currentSchema, id: ULID.make(), name: split.name, color: split.color, systemImage: split.icon, order: order, createdAt: Date(), updatedAt: Date(), exercises: exercises ) } } /// Writes any starter splits whose name doesn't already exist, appended after /// existing splits. Idempotent against double-taps / partial prior seeds. @MainActor static func seedDefaults(into context: ModelContext, using sync: SyncEngine) async { let existing = (try? context.fetch(FetchDescriptor())) ?? [] let existingNames = Set(existing.map(\.name)) let base = existing.count let fresh = defaultSplitDocuments().filter { !existingNames.contains($0.name) } for (offset, var doc) in fresh.enumerated() { doc.order = base + offset await sync.save(split: doc) } } }