// Generates the bundled starter-split JSON resources for Workouts.
// Deterministic: fixed ULID timestamp (2020-01-01T00:00:00Z) + SHA256-of-label
// randomness, fixed document timestamps, encoder matching DocumentCoder
// (prettyPrinted + sortedKeys + iso8601). Re-running always emits identical bytes.
import Foundation
import CryptoKit

// MARK: - ULID (Crockford base32, 48-bit ms timestamp + 80 deterministic bits)

let crockford = Array("0123456789ABCDEFGHJKMNPQRSTVWXYZ")

func deterministicULID(label: String) -> String {
    let timestampMS: UInt64 = 1_577_836_800_000 // 2020-01-01T00:00:00Z
    var bytes = [UInt8]()
    for shift in stride(from: 40, through: 0, by: -8) {
        bytes.append(UInt8((timestampMS >> UInt64(shift)) & 0xFF))
    }
    let digest = SHA256.hash(data: Data(label.utf8))
    bytes.append(contentsOf: Array(digest).prefix(10))
    precondition(bytes.count == 16)

    // Encode 128 bits as 26 Crockford base32 chars: big-int division by 32, 26 digits.
    var chars = [Character]()
    var num = bytes
    for _ in 0..<26 {
        var remainder = 0
        var quotient = [UInt8]()
        for byte in num {
            let acc = remainder * 256 + Int(byte)
            quotient.append(UInt8(acc / 32))
            remainder = acc % 32
        }
        chars.append(crockford[remainder])
        num = quotient
    }
    return String(chars.reversed())
}

// MARK: - Document shapes (field names must mirror Shared/Model/Documents.swift)

struct MachineSetting: Codable {
    var name: String
    var value: String
}

struct ExerciseDocument: Codable {
    var id: String
    var name: String
    var order: Int
    var sets: Int
    var reps: Int
    var weight: Double
    var loadType: Int
    var durationSeconds: Int
    var machineSettings: [MachineSetting]? = nil
}

struct SplitDocument: Codable {
    var schemaVersion: Int
    var id: String
    var name: String
    var color: String
    var systemImage: String
    var order: Int
    var createdAt: Date
    var updatedAt: Date
    var exercises: [ExerciseDocument]
    var activityType: Int?
    var restSeconds: Int? = nil
    var autoAdvance: Bool? = nil
}

// MARK: - Seed data (canonical source for Workouts/Resources/StarterSplits/*.json)

// `machine: true` emits `machineSettings: []` — marks the exercise machine-based
// (empty = nothing recorded yet), which lights up the machine-settings UI without
// the user having to flip the editor toggle first.
struct Ex { let name: String; var weight: Double = 0; var sets = 4; var reps = 10; var load = 1; var dur = 0; var machine = false }
struct Sp { let name: String; let color: String; let icon: String; let activity: Int; var restSeconds: Int? = nil; var autoAdvance: Bool? = nil; let ex: [Ex] }

let seeds: [Sp] = [
    Sp(name: "Upper Body", color: "blue", icon: "figure.strengthtraining.traditional", activity: 0, ex: [
        Ex(name: "Lat Pull Down", weight: 110, machine: true),
        Ex(name: "Seated Row", weight: 90, machine: true),
        Ex(name: "Shoulder Press", weight: 40, machine: true),
        Ex(name: "Chest Press", weight: 40, machine: true),
        Ex(name: "Tricep Press", weight: 100, machine: true),
        Ex(name: "Arm Curl", weight: 40, machine: true),
    ]),
    Sp(name: "Core", color: "orange", icon: "figure.core.training", activity: 3, ex: [
        Ex(name: "Abdominal", weight: 40, machine: true),
        Ex(name: "Rotary", weight: 40, machine: true),
    ]),
    Sp(name: "Lower Body", color: "green", icon: "figure.run", activity: 0, ex: [
        Ex(name: "Leg Press", weight: 140, machine: true),
        Ex(name: "Leg Curl", weight: 40, machine: true),
        Ex(name: "Leg Extension", weight: 80, machine: true),
        Ex(name: "Abductor", weight: 130, machine: true),
        Ex(name: "Adductor", weight: 130, machine: true),
        Ex(name: "Calfs", weight: 100, machine: true),
    ]),
    Sp(name: "Bodyweight Core", color: "teal", icon: "figure.core.training", activity: 3, ex: [
        Ex(name: "Cat-Cow", sets: 1, reps: 10, load: 0),
        Ex(name: "Dead Bug", sets: 1, reps: 8, load: 0),
        Ex(name: "Bird Dog", sets: 1, reps: 8, load: 0),
        Ex(name: "Plank", sets: 3, reps: 0, load: 2, dur: 45),
        Ex(name: "Hollow Body Hold", sets: 3, reps: 0, load: 2, dur: 30),
        Ex(name: "Side Plank", sets: 3, reps: 0, load: 2, dur: 30),
        Ex(name: "Leg Raises", sets: 3, reps: 12, load: 0),
        Ex(name: "Crunch", sets: 3, reps: 12, load: 0),
        Ex(name: "Reverse Crunch", sets: 3, reps: 12, load: 0),
    ]),
    Sp(name: "Full Body Machines", color: "purple", icon: "figure.strengthtraining.traditional", activity: 0, ex: [
        Ex(name: "Leg Press", weight: 100, machine: true),
        Ex(name: "Chest Press", weight: 40, machine: true),
        Ex(name: "Seated Row", weight: 70, machine: true),
        Ex(name: "Shoulder Press", weight: 30, machine: true),
        Ex(name: "Lat Pull Down", weight: 80, machine: true),
        Ex(name: "Abdominal", weight: 40, machine: true),
    ]),
    Sp(name: "Free Weight Basics", color: "red", icon: "dumbbell.fill", activity: 0, ex: [
        Ex(name: "Goblet Squat", weight: 25, sets: 3, reps: 10),
        Ex(name: "Dumbbell Bench Press", weight: 25, sets: 3, reps: 8),
        Ex(name: "Dumbbell Row", weight: 30, sets: 3, reps: 8),
        Ex(name: "Dumbbell Shoulder Press", weight: 20, sets: 3, reps: 8),
        Ex(name: "Romanian Deadlift", weight: 65, sets: 3, reps: 8),
        Ex(name: "Dumbbell Curl", weight: 20, sets: 3, reps: 10),
    ]),
    Sp(name: "Upper Body Warm-Up", color: "cyan", icon: "figure.arms.open", activity: 6, ex: [
        Ex(name: "Arm Circles", sets: 2, reps: 10, load: 0),
        Ex(name: "Torso Twist", sets: 2, reps: 10, load: 0),
        Ex(name: "Standing Side Bend", sets: 2, reps: 8, load: 0),
        Ex(name: "Cat-Cow", sets: 1, reps: 8, load: 0),
        Ex(name: "Push-Up", sets: 2, reps: 8, load: 0),
    ]),
    Sp(name: "Lower Body Warm-Up", color: "mint", icon: "figure.walk", activity: 6, ex: [
        Ex(name: "March in Place", sets: 1, reps: 0, load: 2, dur: 60),
        Ex(name: "Leg Swings", sets: 2, reps: 10, load: 0),
        Ex(name: "Hip Circles", sets: 2, reps: 8, load: 0),
        Ex(name: "Bodyweight Squat", sets: 2, reps: 12, load: 0),
        Ex(name: "Glute Bridge", sets: 2, reps: 10, load: 0),
        Ex(name: "Standing Calf Raise", sets: 2, reps: 12, load: 0),
    ]),
    Sp(name: "Morning Wake-Up", color: "yellow", icon: "sun.max.fill", activity: 6, restSeconds: 15, autoAdvance: true, ex: [
        Ex(name: "March in Place", sets: 1, reps: 0, load: 2, dur: 45),
        Ex(name: "Neck Rolls", sets: 1, reps: 0, load: 2, dur: 45),
        Ex(name: "Arm Circles", sets: 1, reps: 0, load: 2, dur: 45),
        Ex(name: "Torso Twist", sets: 1, reps: 0, load: 2, dur: 45),
        Ex(name: "Standing Side Bend", sets: 1, reps: 0, load: 2, dur: 45),
        Ex(name: "Hip Circles", sets: 1, reps: 0, load: 2, dur: 45),
        Ex(name: "Leg Swings", sets: 1, reps: 0, load: 2, dur: 45),
        Ex(name: "Standing Calf Raise", sets: 1, reps: 0, load: 2, dur: 45),
        Ex(name: "Standing Forward Fold", sets: 1, reps: 0, load: 2, dur: 45),
    ]),
    Sp(name: "Morning Mobility", color: "pink", icon: "figure.yoga", activity: 7, ex: [
        Ex(name: "Cat-Cow", sets: 1, reps: 10, load: 0),
        Ex(name: "Bird Dog", sets: 1, reps: 8, load: 0),
        Ex(name: "Dead Bug", sets: 1, reps: 8, load: 0),
        Ex(name: "Glute Bridge", sets: 1, reps: 12, load: 0),
        Ex(name: "Cobra Stretch", sets: 1, reps: 8, load: 0),
        Ex(name: "Child's Pose", sets: 1, reps: 0, load: 2, dur: 45),
        Ex(name: "Standing Forward Fold", sets: 1, reps: 0, load: 2, dur: 30),
    ]),
    Sp(name: "Full Body Stretch", color: "brown", icon: "figure.flexibility", activity: 7, ex: [
        Ex(name: "Standing Forward Fold", sets: 1, reps: 0, load: 2, dur: 30),
        Ex(name: "Standing Quad Stretch", sets: 2, reps: 0, load: 2, dur: 30),
        Ex(name: "Standing Calf Stretch", sets: 2, reps: 0, load: 2, dur: 30),
        Ex(name: "Chest Opener", sets: 1, reps: 0, load: 2, dur: 30),
        Ex(name: "Overhead Triceps Stretch", sets: 2, reps: 0, load: 2, dur: 30),
        Ex(name: "Kneeling Hip Flexor Stretch", sets: 2, reps: 0, load: 2, dur: 30),
        Ex(name: "Child's Pose", sets: 1, reps: 0, load: 2, dur: 45),
    ]),
    Sp(name: "Evening Stretch", color: "indigo", icon: "figure.mind.and.body", activity: 7, ex: [
        Ex(name: "Cat-Cow", sets: 1, reps: 10, load: 0),
        Ex(name: "Butterfly Stretch", sets: 1, reps: 0, load: 2, dur: 45),
        Ex(name: "Kneeling Hip Flexor Stretch", sets: 2, reps: 0, load: 2, dur: 30),
        Ex(name: "Cobra Stretch", sets: 1, reps: 8, load: 0),
        Ex(name: "Child's Pose", sets: 1, reps: 0, load: 2, dur: 45),
    ]),
    // A single generic, watch-tracked cardio block: one duration exercise in a
    // `.cardio` (→ HealthKit `.mixedCardio`) split. The phone logs the time; the
    // watch records the real workout (heart rate, calories, duration).
    Sp(name: "Cardio", color: "red", icon: "figure.run", activity: 4, ex: [
        Ex(name: "Cardio", sets: 1, reps: 0, load: 2, dur: 1200),
    ]),
    // A single timed sit in a `.mindAndBody` (→ HealthKit `.mindAndBody`) split,
    // same one-block shape as Cardio.
    Sp(name: "Meditation", color: "purple", icon: "figure.mind.and.body", activity: 8, ex: [
        Ex(name: "Meditation", sets: 1, reps: 0, load: 2, dur: 300),
    ]),
]

// MARK: - Emit

let encoder = JSONEncoder()
encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
encoder.dateEncodingStrategy = .iso8601

let fixedDate = ISO8601DateFormatter().date(from: "2020-01-01T00:00:00Z")!
let outDir = URL(fileURLWithPath: CommandLine.arguments[1], isDirectory: true)
try FileManager.default.createDirectory(at: outDir, withIntermediateDirectories: true)

for (order, sp) in seeds.enumerated() {
    let slug = sp.name.lowercased().replacingOccurrences(of: " ", with: "-")
    let doc = SplitDocument(
        schemaVersion: 3,
        id: deterministicULID(label: "starter.\(slug)"),
        name: sp.name, color: sp.color, systemImage: sp.icon, order: order,
        createdAt: fixedDate, updatedAt: fixedDate,
        exercises: sp.ex.enumerated().map { idx, e in
            ExerciseDocument(
                id: deterministicULID(label: "starter.\(slug).ex\(idx)"),
                name: e.name, order: idx, sets: e.sets, reps: e.reps, weight: e.weight,
                loadType: e.load, durationSeconds: e.dur,
                machineSettings: e.machine ? [] : nil)
        },
        activityType: sp.activity,
        restSeconds: sp.restSeconds, autoAdvance: sp.autoAdvance)
    let data = try encoder.encode(doc)
    let file = outDir.appendingPathComponent("\(sp.name).split.json")
    try data.write(to: file)
    print("\(doc.id)  \(sp.name)  (\(sp.ex.count) exercises)")
}
